1488570ebSJim Harris /* SPDX-License-Identifier: BSD-3-Clause 2a6dbe372Spaul luse * Copyright (C) 2017 Intel Corporation. 307fe6a43SSeth Howell * All rights reserved. 407fe6a43SSeth Howell */ 507fe6a43SSeth Howell 607fe6a43SSeth Howell /* 707fe6a43SSeth Howell * This is a module for test purpose which will simulate error cases for bdev. 807fe6a43SSeth Howell */ 907fe6a43SSeth Howell 1007fe6a43SSeth Howell #include "spdk/stdinc.h" 1107fe6a43SSeth Howell #include "spdk/rpc.h" 1207fe6a43SSeth Howell #include "spdk/util.h" 1307fe6a43SSeth Howell #include "spdk/endian.h" 1407fe6a43SSeth Howell #include "spdk/nvme_spec.h" 1507fe6a43SSeth Howell #include "spdk/string.h" 1607fe6a43SSeth Howell 1707fe6a43SSeth Howell #include "spdk/bdev_module.h" 184e8e97c8STomasz Zawadzki #include "spdk/log.h" 1907fe6a43SSeth Howell 2007fe6a43SSeth Howell #include "vbdev_error.h" 2107fe6a43SSeth Howell 2207fe6a43SSeth Howell struct spdk_vbdev_error_config { 2307fe6a43SSeth Howell char *base_bdev; 2491ea8102SKrzysztof Karas struct spdk_uuid uuid; 2507fe6a43SSeth Howell TAILQ_ENTRY(spdk_vbdev_error_config) tailq; 2607fe6a43SSeth Howell }; 2707fe6a43SSeth Howell 2807fe6a43SSeth Howell static TAILQ_HEAD(, spdk_vbdev_error_config) g_error_config 2907fe6a43SSeth Howell = TAILQ_HEAD_INITIALIZER(g_error_config); 3007fe6a43SSeth Howell 3107fe6a43SSeth Howell struct vbdev_error_info { 3207fe6a43SSeth Howell uint32_t error_type; 3307fe6a43SSeth Howell uint32_t error_num; 344dacace1SArtur Paszkiewicz uint64_t error_qd; 353d2a3ee4SShuhei Matsumoto uint64_t corrupt_offset; 363d2a3ee4SShuhei Matsumoto uint8_t corrupt_value; 3707fe6a43SSeth Howell }; 3807fe6a43SSeth Howell 3979909446SBen Walker struct error_io { 40e55c9a81SNathan Claudel enum vbdev_error_type error_type; 4179909446SBen Walker TAILQ_ENTRY(error_io) link; 4279909446SBen Walker }; 4379909446SBen Walker 4407fe6a43SSeth Howell /* Context for each error bdev */ 4507fe6a43SSeth Howell struct error_disk { 4607fe6a43SSeth Howell struct spdk_bdev_part part; 4707fe6a43SSeth Howell struct vbdev_error_info error_vector[SPDK_BDEV_IO_TYPE_RESET]; 4807fe6a43SSeth Howell }; 4907fe6a43SSeth Howell 5007fe6a43SSeth Howell struct error_channel { 5107fe6a43SSeth Howell struct spdk_bdev_part_channel part_ch; 524dacace1SArtur Paszkiewicz uint64_t io_inflight; 53c164db9fSJinlong Chen TAILQ_HEAD(, error_io) pending_ios; 5407fe6a43SSeth Howell }; 5507fe6a43SSeth Howell 5607fe6a43SSeth Howell static pthread_mutex_t g_vbdev_error_mutex = PTHREAD_MUTEX_INITIALIZER; 5707fe6a43SSeth Howell static SPDK_BDEV_PART_TAILQ g_error_disks = TAILQ_HEAD_INITIALIZER(g_error_disks); 5807fe6a43SSeth Howell 5907fe6a43SSeth Howell static int vbdev_error_init(void); 6007fe6a43SSeth Howell static void vbdev_error_fini(void); 6107fe6a43SSeth Howell 6207fe6a43SSeth Howell static void vbdev_error_examine(struct spdk_bdev *bdev); 6307fe6a43SSeth Howell static int vbdev_error_config_json(struct spdk_json_write_ctx *w); 6407fe6a43SSeth Howell 6591ea8102SKrzysztof Karas static int vbdev_error_config_add(const char *base_bdev_name, const struct spdk_uuid *uuid); 6607fe6a43SSeth Howell static int vbdev_error_config_remove(const char *base_bdev_name); 6707fe6a43SSeth Howell 6879909446SBen Walker static int 6979909446SBen Walker vbdev_error_get_ctx_size(void) 7079909446SBen Walker { 7179909446SBen Walker return sizeof(struct error_io); 7279909446SBen Walker } 7379909446SBen Walker 7407fe6a43SSeth Howell static struct spdk_bdev_module error_if = { 7507fe6a43SSeth Howell .name = "error", 7607fe6a43SSeth Howell .module_init = vbdev_error_init, 7707fe6a43SSeth Howell .module_fini = vbdev_error_fini, 7807fe6a43SSeth Howell .examine_config = vbdev_error_examine, 7907fe6a43SSeth Howell .config_json = vbdev_error_config_json, 8079909446SBen Walker .get_ctx_size = vbdev_error_get_ctx_size, 8107fe6a43SSeth Howell 8207fe6a43SSeth Howell }; 8307fe6a43SSeth Howell 8407fe6a43SSeth Howell SPDK_BDEV_MODULE_REGISTER(error, &error_if) 8507fe6a43SSeth Howell 86cf1e19c7SShuhei Matsumoto static void 87cf1e19c7SShuhei Matsumoto dummy_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *ctx) 88cf1e19c7SShuhei Matsumoto { 89cf1e19c7SShuhei Matsumoto } 90cf1e19c7SShuhei Matsumoto 9107fe6a43SSeth Howell int 92ffee98ddSShuhei Matsumoto vbdev_error_inject_error(char *name, const struct vbdev_error_inject_opts *opts) 9307fe6a43SSeth Howell { 94cf1e19c7SShuhei Matsumoto struct spdk_bdev_desc *desc; 9507fe6a43SSeth Howell struct spdk_bdev *bdev; 9607fe6a43SSeth Howell struct spdk_bdev_part *part; 9707fe6a43SSeth Howell struct error_disk *error_disk = NULL; 9807fe6a43SSeth Howell uint32_t i; 99cf1e19c7SShuhei Matsumoto int rc = 0; 10007fe6a43SSeth Howell 1013d2a3ee4SShuhei Matsumoto if (opts->error_type == VBDEV_IO_CORRUPT_DATA) { 1023d2a3ee4SShuhei Matsumoto if (opts->corrupt_value == 0) { 1033d2a3ee4SShuhei Matsumoto /* If corrupt_value is 0, XOR cannot cause data corruption. */ 1043d2a3ee4SShuhei Matsumoto SPDK_ERRLOG("corrupt_value should be non-zero.\n"); 1053d2a3ee4SShuhei Matsumoto return -EINVAL; 1063d2a3ee4SShuhei Matsumoto } 1073d2a3ee4SShuhei Matsumoto } 1083d2a3ee4SShuhei Matsumoto 10907fe6a43SSeth Howell pthread_mutex_lock(&g_vbdev_error_mutex); 110cf1e19c7SShuhei Matsumoto 111cf1e19c7SShuhei Matsumoto rc = spdk_bdev_open_ext(name, false, dummy_bdev_event_cb, NULL, &desc); 112cf1e19c7SShuhei Matsumoto if (rc != 0) { 113cf1e19c7SShuhei Matsumoto SPDK_ERRLOG("Could not open ErrorInjection bdev %s\n", name); 11407fe6a43SSeth Howell pthread_mutex_unlock(&g_vbdev_error_mutex); 115cf1e19c7SShuhei Matsumoto return rc; 11607fe6a43SSeth Howell } 11707fe6a43SSeth Howell 118cf1e19c7SShuhei Matsumoto bdev = spdk_bdev_desc_get_bdev(desc); 119cf1e19c7SShuhei Matsumoto 12007fe6a43SSeth Howell TAILQ_FOREACH(part, &g_error_disks, tailq) { 12107fe6a43SSeth Howell if (bdev == spdk_bdev_part_get_bdev(part)) { 12207fe6a43SSeth Howell error_disk = (struct error_disk *)part; 12307fe6a43SSeth Howell break; 12407fe6a43SSeth Howell } 12507fe6a43SSeth Howell } 12607fe6a43SSeth Howell 12707fe6a43SSeth Howell if (error_disk == NULL) { 12807fe6a43SSeth Howell SPDK_ERRLOG("Could not find ErrorInjection bdev %s\n", name); 129cf1e19c7SShuhei Matsumoto rc = -ENODEV; 130cf1e19c7SShuhei Matsumoto goto exit; 13107fe6a43SSeth Howell } 13207fe6a43SSeth Howell 133ffee98ddSShuhei Matsumoto if (0xffffffff == opts->io_type) { 13407fe6a43SSeth Howell for (i = 0; i < SPDK_COUNTOF(error_disk->error_vector); i++) { 135ffee98ddSShuhei Matsumoto error_disk->error_vector[i].error_type = opts->error_type; 136ffee98ddSShuhei Matsumoto error_disk->error_vector[i].error_num = opts->error_num; 1374dacace1SArtur Paszkiewicz error_disk->error_vector[i].error_qd = opts->error_qd; 1383d2a3ee4SShuhei Matsumoto error_disk->error_vector[i].corrupt_offset = opts->corrupt_offset; 1393d2a3ee4SShuhei Matsumoto error_disk->error_vector[i].corrupt_value = opts->corrupt_value; 14007fe6a43SSeth Howell } 141ffee98ddSShuhei Matsumoto } else if (0 == opts->io_type) { 14207fe6a43SSeth Howell for (i = 0; i < SPDK_COUNTOF(error_disk->error_vector); i++) { 14307fe6a43SSeth Howell error_disk->error_vector[i].error_num = 0; 14407fe6a43SSeth Howell } 14507fe6a43SSeth Howell } else { 146ffee98ddSShuhei Matsumoto error_disk->error_vector[opts->io_type].error_type = opts->error_type; 147ffee98ddSShuhei Matsumoto error_disk->error_vector[opts->io_type].error_num = opts->error_num; 1484dacace1SArtur Paszkiewicz error_disk->error_vector[opts->io_type].error_qd = opts->error_qd; 1493d2a3ee4SShuhei Matsumoto error_disk->error_vector[opts->io_type].corrupt_offset = opts->corrupt_offset; 1503d2a3ee4SShuhei Matsumoto error_disk->error_vector[opts->io_type].corrupt_value = opts->corrupt_value; 15107fe6a43SSeth Howell } 152cf1e19c7SShuhei Matsumoto 153cf1e19c7SShuhei Matsumoto exit: 154cf1e19c7SShuhei Matsumoto spdk_bdev_close(desc); 15507fe6a43SSeth Howell pthread_mutex_unlock(&g_vbdev_error_mutex); 156cf1e19c7SShuhei Matsumoto return rc; 15707fe6a43SSeth Howell } 15807fe6a43SSeth Howell 15907fe6a43SSeth Howell static void 160c164db9fSJinlong Chen vbdev_error_ch_abort_ios(struct spdk_io_channel_iter *i) 161c164db9fSJinlong Chen { 162c164db9fSJinlong Chen struct error_channel *ch = spdk_io_channel_get_ctx(spdk_io_channel_iter_get_channel(i)); 163c164db9fSJinlong Chen struct error_io *error_io, *tmp; 164c164db9fSJinlong Chen 165c164db9fSJinlong Chen TAILQ_FOREACH_SAFE(error_io, &ch->pending_ios, link, tmp) { 166c164db9fSJinlong Chen TAILQ_REMOVE(&ch->pending_ios, error_io, link); 167c164db9fSJinlong Chen spdk_bdev_io_complete(spdk_bdev_io_from_ctx(error_io), SPDK_BDEV_IO_STATUS_ABORTED); 168c164db9fSJinlong Chen } 169c164db9fSJinlong Chen 170c164db9fSJinlong Chen spdk_for_each_channel_continue(i, 0); 171c164db9fSJinlong Chen } 172c164db9fSJinlong Chen 173c164db9fSJinlong Chen static void 174c164db9fSJinlong Chen vbdev_error_ch_abort_ios_done(struct spdk_io_channel_iter *i, int status) 175c164db9fSJinlong Chen { 176c164db9fSJinlong Chen struct spdk_bdev_io *reset_io = spdk_io_channel_iter_get_ctx(i); 177c164db9fSJinlong Chen 178c164db9fSJinlong Chen if (status != 0) { 179c164db9fSJinlong Chen SPDK_ERRLOG("Failed to abort pending I/Os on bdev %s, status = %d\n", 180c164db9fSJinlong Chen reset_io->bdev->name, status); 181c164db9fSJinlong Chen spdk_bdev_io_complete(reset_io, SPDK_BDEV_IO_STATUS_FAILED); 182c164db9fSJinlong Chen } else { 183c164db9fSJinlong Chen spdk_bdev_io_complete(reset_io, SPDK_BDEV_IO_STATUS_SUCCESS); 184c164db9fSJinlong Chen } 185c164db9fSJinlong Chen } 186c164db9fSJinlong Chen 187c164db9fSJinlong Chen static void 18807fe6a43SSeth Howell vbdev_error_reset(struct error_disk *error_disk, struct spdk_bdev_io *bdev_io) 18907fe6a43SSeth Howell { 190c164db9fSJinlong Chen spdk_for_each_channel(&error_disk->part, vbdev_error_ch_abort_ios, bdev_io, 191c164db9fSJinlong Chen vbdev_error_ch_abort_ios_done); 19207fe6a43SSeth Howell } 19307fe6a43SSeth Howell 19407fe6a43SSeth Howell static uint32_t 195e55c9a81SNathan Claudel vbdev_error_get_error_type(struct error_disk *error_disk, struct error_channel *ch, 196e55c9a81SNathan Claudel uint32_t io_type) 19707fe6a43SSeth Howell { 198e55c9a81SNathan Claudel uint32_t error_num; 199e55c9a81SNathan Claudel struct vbdev_error_info *error_info; 200e55c9a81SNathan Claudel 2017078874bSShuhei Matsumoto switch (io_type) { 2027078874bSShuhei Matsumoto case SPDK_BDEV_IO_TYPE_READ: 2037078874bSShuhei Matsumoto case SPDK_BDEV_IO_TYPE_WRITE: 2047078874bSShuhei Matsumoto case SPDK_BDEV_IO_TYPE_UNMAP: 2057078874bSShuhei Matsumoto case SPDK_BDEV_IO_TYPE_FLUSH: 2067078874bSShuhei Matsumoto break; 2077078874bSShuhei Matsumoto default: 208e55c9a81SNathan Claudel return VBDEV_IO_NO_ERROR; 2097078874bSShuhei Matsumoto } 2107078874bSShuhei Matsumoto 211e55c9a81SNathan Claudel error_info = &error_disk->error_vector[io_type]; 212e55c9a81SNathan Claudel 213e55c9a81SNathan Claudel if (ch->io_inflight < error_info->error_qd) { 214e55c9a81SNathan Claudel return VBDEV_IO_NO_ERROR; 21507fe6a43SSeth Howell } 216e55c9a81SNathan Claudel 217e55c9a81SNathan Claudel error_num = error_info->error_num; 218e55c9a81SNathan Claudel do { 219e55c9a81SNathan Claudel if (error_num == 0) { 220e55c9a81SNathan Claudel return VBDEV_IO_NO_ERROR; 221e55c9a81SNathan Claudel } 222e55c9a81SNathan Claudel } while (!__atomic_compare_exchange_n(&error_info->error_num, 223e55c9a81SNathan Claudel &error_num, error_num - 1, 224e55c9a81SNathan Claudel false, __ATOMIC_RELAXED, __ATOMIC_RELAXED)); 225e55c9a81SNathan Claudel 226e55c9a81SNathan Claudel return error_info->error_type; 22707fe6a43SSeth Howell } 22807fe6a43SSeth Howell 22907fe6a43SSeth Howell static void 2303d2a3ee4SShuhei Matsumoto vbdev_error_corrupt_io_data(struct spdk_bdev_io *bdev_io, uint64_t corrupt_offset, 2313d2a3ee4SShuhei Matsumoto uint8_t corrupt_value) 2323d2a3ee4SShuhei Matsumoto { 2333d2a3ee4SShuhei Matsumoto uint8_t *buf; 2343d2a3ee4SShuhei Matsumoto int i; 2353d2a3ee4SShuhei Matsumoto 2363d2a3ee4SShuhei Matsumoto if (bdev_io->u.bdev.iovs == NULL || bdev_io->u.bdev.iovs[0].iov_base == NULL) { 2373d2a3ee4SShuhei Matsumoto return; 2383d2a3ee4SShuhei Matsumoto } 2393d2a3ee4SShuhei Matsumoto 2403d2a3ee4SShuhei Matsumoto for (i = 0; i < bdev_io->u.bdev.iovcnt; i++) { 2413d2a3ee4SShuhei Matsumoto if (bdev_io->u.bdev.iovs[i].iov_len > corrupt_offset) { 2423d2a3ee4SShuhei Matsumoto buf = (uint8_t *)bdev_io->u.bdev.iovs[i].iov_base; 2433d2a3ee4SShuhei Matsumoto 2443d2a3ee4SShuhei Matsumoto buf[corrupt_offset] ^= corrupt_value; 2453d2a3ee4SShuhei Matsumoto break; 2463d2a3ee4SShuhei Matsumoto } 2473d2a3ee4SShuhei Matsumoto 2483d2a3ee4SShuhei Matsumoto corrupt_offset -= bdev_io->u.bdev.iovs[i].iov_len; 2493d2a3ee4SShuhei Matsumoto } 2503d2a3ee4SShuhei Matsumoto } 2513d2a3ee4SShuhei Matsumoto 2523d2a3ee4SShuhei Matsumoto static void 253e0daee98SShuhei Matsumoto vbdev_error_complete_request(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg) 254e0daee98SShuhei Matsumoto { 255e55c9a81SNathan Claudel struct error_io *error_io = (struct error_io *)bdev_io->driver_ctx; 256e0daee98SShuhei Matsumoto int status = success ? SPDK_BDEV_IO_STATUS_SUCCESS : SPDK_BDEV_IO_STATUS_FAILED; 2573d2a3ee4SShuhei Matsumoto struct error_disk *error_disk = bdev_io->bdev->ctxt; 2584dacace1SArtur Paszkiewicz struct error_channel *ch = spdk_io_channel_get_ctx(spdk_bdev_io_get_io_channel(bdev_io)); 2593d2a3ee4SShuhei Matsumoto 2604dacace1SArtur Paszkiewicz assert(ch->io_inflight > 0); 2614dacace1SArtur Paszkiewicz ch->io_inflight--; 2624dacace1SArtur Paszkiewicz 2633d2a3ee4SShuhei Matsumoto if (success && bdev_io->type == SPDK_BDEV_IO_TYPE_READ) { 264e55c9a81SNathan Claudel if (error_io->error_type == VBDEV_IO_CORRUPT_DATA) { 2653d2a3ee4SShuhei Matsumoto vbdev_error_corrupt_io_data(bdev_io, 2663d2a3ee4SShuhei Matsumoto error_disk->error_vector[bdev_io->type].corrupt_offset, 2673d2a3ee4SShuhei Matsumoto error_disk->error_vector[bdev_io->type].corrupt_value); 2683d2a3ee4SShuhei Matsumoto } 2693d2a3ee4SShuhei Matsumoto } 270e0daee98SShuhei Matsumoto 271e0daee98SShuhei Matsumoto spdk_bdev_io_complete(bdev_io, status); 272e0daee98SShuhei Matsumoto } 273e0daee98SShuhei Matsumoto 274e0daee98SShuhei Matsumoto static void 27507fe6a43SSeth Howell vbdev_error_submit_request(struct spdk_io_channel *_ch, struct spdk_bdev_io *bdev_io) 27607fe6a43SSeth Howell { 27779909446SBen Walker struct error_io *error_io = (struct error_io *)bdev_io->driver_ctx; 27807fe6a43SSeth Howell struct error_channel *ch = spdk_io_channel_get_ctx(_ch); 27907fe6a43SSeth Howell struct error_disk *error_disk = bdev_io->bdev->ctxt; 280fa5e7d1bSShuhei Matsumoto int rc; 28107fe6a43SSeth Howell 2827078874bSShuhei Matsumoto if (bdev_io->type == SPDK_BDEV_IO_TYPE_RESET) { 28307fe6a43SSeth Howell vbdev_error_reset(error_disk, bdev_io); 28407fe6a43SSeth Howell return; 28507fe6a43SSeth Howell } 28607fe6a43SSeth Howell 287e55c9a81SNathan Claudel error_io->error_type = vbdev_error_get_error_type(error_disk, ch, bdev_io->type); 2884dacace1SArtur Paszkiewicz 289e55c9a81SNathan Claudel switch (error_io->error_type) { 290fa5e7d1bSShuhei Matsumoto case VBDEV_IO_FAILURE: 291fa5e7d1bSShuhei Matsumoto spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 292fa5e7d1bSShuhei Matsumoto break; 293408a2155SArtur Paszkiewicz case VBDEV_IO_NOMEM: 294408a2155SArtur Paszkiewicz spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_NOMEM); 295408a2155SArtur Paszkiewicz break; 296fa5e7d1bSShuhei Matsumoto case VBDEV_IO_PENDING: 297c164db9fSJinlong Chen TAILQ_INSERT_TAIL(&ch->pending_ios, error_io, link); 298fa5e7d1bSShuhei Matsumoto break; 2993d2a3ee4SShuhei Matsumoto case VBDEV_IO_CORRUPT_DATA: 3003d2a3ee4SShuhei Matsumoto if (bdev_io->type == SPDK_BDEV_IO_TYPE_WRITE) { 3013d2a3ee4SShuhei Matsumoto vbdev_error_corrupt_io_data(bdev_io, 3023d2a3ee4SShuhei Matsumoto error_disk->error_vector[bdev_io->type].corrupt_offset, 3033d2a3ee4SShuhei Matsumoto error_disk->error_vector[bdev_io->type].corrupt_value); 3043d2a3ee4SShuhei Matsumoto } 3053d2a3ee4SShuhei Matsumoto /* fallthrough */ 306e55c9a81SNathan Claudel case VBDEV_IO_NO_ERROR: 307*f2f4b5f2SJinlong Chen ch->io_inflight++; 308e0daee98SShuhei Matsumoto rc = spdk_bdev_part_submit_request_ext(&ch->part_ch, bdev_io, 309e0daee98SShuhei Matsumoto vbdev_error_complete_request); 31007fe6a43SSeth Howell 31107fe6a43SSeth Howell if (rc) { 31207fe6a43SSeth Howell SPDK_ERRLOG("bdev_error: submit request failed, rc=%d\n", rc); 31307fe6a43SSeth Howell spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 314*f2f4b5f2SJinlong Chen ch->io_inflight--; 31507fe6a43SSeth Howell } 316fa5e7d1bSShuhei Matsumoto break; 317fa5e7d1bSShuhei Matsumoto default: 318fa5e7d1bSShuhei Matsumoto assert(false); 319fa5e7d1bSShuhei Matsumoto break; 32007fe6a43SSeth Howell } 32107fe6a43SSeth Howell } 32207fe6a43SSeth Howell 32307fe6a43SSeth Howell static int 32407fe6a43SSeth Howell vbdev_error_destruct(void *ctx) 32507fe6a43SSeth Howell { 32607fe6a43SSeth Howell struct error_disk *error_disk = ctx; 32707fe6a43SSeth Howell struct spdk_bdev *base_bdev = spdk_bdev_part_get_base_bdev(&error_disk->part); 32807fe6a43SSeth Howell int rc; 32907fe6a43SSeth Howell 33007fe6a43SSeth Howell rc = vbdev_error_config_remove(base_bdev->name); 33107fe6a43SSeth Howell if (rc != 0) { 33207fe6a43SSeth Howell SPDK_ERRLOG("vbdev_error_config_remove() failed\n"); 33307fe6a43SSeth Howell } 33407fe6a43SSeth Howell 33507fe6a43SSeth Howell return spdk_bdev_part_free(&error_disk->part); 33607fe6a43SSeth Howell } 33707fe6a43SSeth Howell 33807fe6a43SSeth Howell static int 33907fe6a43SSeth Howell vbdev_error_dump_info_json(void *ctx, struct spdk_json_write_ctx *w) 34007fe6a43SSeth Howell { 34107fe6a43SSeth Howell struct error_disk *error_disk = ctx; 34207fe6a43SSeth Howell struct spdk_bdev *base_bdev = spdk_bdev_part_get_base_bdev(&error_disk->part); 34307fe6a43SSeth Howell 34407fe6a43SSeth Howell spdk_json_write_named_object_begin(w, "error_disk"); 34507fe6a43SSeth Howell 34607fe6a43SSeth Howell spdk_json_write_named_string(w, "base_bdev", base_bdev->name); 34707fe6a43SSeth Howell 34807fe6a43SSeth Howell spdk_json_write_object_end(w); 34907fe6a43SSeth Howell 35007fe6a43SSeth Howell return 0; 35107fe6a43SSeth Howell } 35207fe6a43SSeth Howell 35307fe6a43SSeth Howell static void 35407fe6a43SSeth Howell vbdev_error_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w) 35507fe6a43SSeth Howell { 35607fe6a43SSeth Howell /* No config per bdev. */ 35707fe6a43SSeth Howell } 35807fe6a43SSeth Howell 35907fe6a43SSeth Howell 36007fe6a43SSeth Howell static struct spdk_bdev_fn_table vbdev_error_fn_table = { 36107fe6a43SSeth Howell .destruct = vbdev_error_destruct, 36207fe6a43SSeth Howell .submit_request = vbdev_error_submit_request, 36307fe6a43SSeth Howell .dump_info_json = vbdev_error_dump_info_json, 36407fe6a43SSeth Howell .write_config_json = vbdev_error_write_config_json 36507fe6a43SSeth Howell }; 36607fe6a43SSeth Howell 36707fe6a43SSeth Howell static void 368ef78704fSSeth Howell vbdev_error_base_bdev_hotremove_cb(void *_part_base) 36907fe6a43SSeth Howell { 37007fe6a43SSeth Howell struct spdk_bdev_part_base *part_base = _part_base; 37107fe6a43SSeth Howell 37207fe6a43SSeth Howell spdk_bdev_part_base_hotremove(part_base, &g_error_disks); 37307fe6a43SSeth Howell } 37407fe6a43SSeth Howell 37507fe6a43SSeth Howell static int 376c164db9fSJinlong Chen vbdev_error_ch_create_cb(void *io_device, void *ctx_buf) 377c164db9fSJinlong Chen { 378c164db9fSJinlong Chen struct error_channel *ch = ctx_buf; 379c164db9fSJinlong Chen 380c164db9fSJinlong Chen ch->io_inflight = 0; 381c164db9fSJinlong Chen TAILQ_INIT(&ch->pending_ios); 382c164db9fSJinlong Chen 383c164db9fSJinlong Chen return 0; 384c164db9fSJinlong Chen } 385c164db9fSJinlong Chen 386c164db9fSJinlong Chen static void 387c164db9fSJinlong Chen vbdev_error_ch_destroy_cb(void *io_device, void *ctx_buf) 388c164db9fSJinlong Chen { 389c164db9fSJinlong Chen } 390c164db9fSJinlong Chen 391c164db9fSJinlong Chen static int 39291ea8102SKrzysztof Karas _vbdev_error_create(const char *base_bdev_name, const struct spdk_uuid *uuid) 39307fe6a43SSeth Howell { 39407fe6a43SSeth Howell struct spdk_bdev_part_base *base = NULL; 39507fe6a43SSeth Howell struct error_disk *disk = NULL; 39691ea8102SKrzysztof Karas struct spdk_bdev *base_bdev, *bdev; 39707fe6a43SSeth Howell char *name; 39807fe6a43SSeth Howell int rc; 39907fe6a43SSeth Howell 4005bb0d8f2SShuhei Matsumoto rc = spdk_bdev_part_base_construct_ext(base_bdev_name, 401ef78704fSSeth Howell vbdev_error_base_bdev_hotremove_cb, 40207fe6a43SSeth Howell &error_if, &vbdev_error_fn_table, &g_error_disks, 40307fe6a43SSeth Howell NULL, NULL, sizeof(struct error_channel), 404c164db9fSJinlong Chen vbdev_error_ch_create_cb, vbdev_error_ch_destroy_cb, 405c164db9fSJinlong Chen &base); 4065bb0d8f2SShuhei Matsumoto if (rc != 0) { 4075bb0d8f2SShuhei Matsumoto if (rc != -ENODEV) { 4085bb0d8f2SShuhei Matsumoto SPDK_ERRLOG("could not construct part base for bdev %s\n", base_bdev_name); 40907fe6a43SSeth Howell } 4105bb0d8f2SShuhei Matsumoto return rc; 4115bb0d8f2SShuhei Matsumoto } 4125bb0d8f2SShuhei Matsumoto 4135bb0d8f2SShuhei Matsumoto base_bdev = spdk_bdev_part_base_get_bdev(base); 41407fe6a43SSeth Howell 41507fe6a43SSeth Howell disk = calloc(1, sizeof(*disk)); 41607fe6a43SSeth Howell if (!disk) { 41707fe6a43SSeth Howell SPDK_ERRLOG("Memory allocation failure\n"); 41807fe6a43SSeth Howell spdk_bdev_part_base_free(base); 41907fe6a43SSeth Howell return -ENOMEM; 42007fe6a43SSeth Howell } 42107fe6a43SSeth Howell 4225bb0d8f2SShuhei Matsumoto name = spdk_sprintf_alloc("EE_%s", base_bdev_name); 42307fe6a43SSeth Howell if (!name) { 42407fe6a43SSeth Howell SPDK_ERRLOG("name allocation failure\n"); 42507fe6a43SSeth Howell spdk_bdev_part_base_free(base); 42607fe6a43SSeth Howell free(disk); 42707fe6a43SSeth Howell return -ENOMEM; 42807fe6a43SSeth Howell } 42907fe6a43SSeth Howell 430e85f1f11SKonrad Sztyber if (!spdk_uuid_is_null(uuid)) { 43191ea8102SKrzysztof Karas bdev = spdk_bdev_part_get_bdev(&disk->part); 43291ea8102SKrzysztof Karas spdk_uuid_copy(&bdev->uuid, uuid); 43391ea8102SKrzysztof Karas } 43491ea8102SKrzysztof Karas 43507fe6a43SSeth Howell rc = spdk_bdev_part_construct(&disk->part, base, name, 0, base_bdev->blockcnt, 43607fe6a43SSeth Howell "Error Injection Disk"); 43707fe6a43SSeth Howell free(name); 43807fe6a43SSeth Howell if (rc) { 4395bb0d8f2SShuhei Matsumoto SPDK_ERRLOG("could not construct part for bdev %s\n", base_bdev_name); 44007fe6a43SSeth Howell /* spdk_bdev_part_construct will free name on failure */ 44107fe6a43SSeth Howell spdk_bdev_part_base_free(base); 44207fe6a43SSeth Howell free(disk); 44307fe6a43SSeth Howell return rc; 44407fe6a43SSeth Howell } 44507fe6a43SSeth Howell 44607fe6a43SSeth Howell return 0; 44707fe6a43SSeth Howell } 44807fe6a43SSeth Howell 44907fe6a43SSeth Howell int 45091ea8102SKrzysztof Karas vbdev_error_create(const char *base_bdev_name, const struct spdk_uuid *uuid) 45107fe6a43SSeth Howell { 45207fe6a43SSeth Howell int rc; 45307fe6a43SSeth Howell 45491ea8102SKrzysztof Karas rc = vbdev_error_config_add(base_bdev_name, uuid); 45507fe6a43SSeth Howell if (rc != 0) { 45607fe6a43SSeth Howell SPDK_ERRLOG("Adding config for ErrorInjection bdev %s failed (rc=%d)\n", 45707fe6a43SSeth Howell base_bdev_name, rc); 45807fe6a43SSeth Howell return rc; 45907fe6a43SSeth Howell } 46007fe6a43SSeth Howell 46191ea8102SKrzysztof Karas rc = _vbdev_error_create(base_bdev_name, uuid); 4625bb0d8f2SShuhei Matsumoto if (rc == -ENODEV) { 4635bb0d8f2SShuhei Matsumoto rc = 0; 4645bb0d8f2SShuhei Matsumoto } else if (rc != 0) { 46507fe6a43SSeth Howell vbdev_error_config_remove(base_bdev_name); 46607fe6a43SSeth Howell SPDK_ERRLOG("Could not create ErrorInjection bdev %s (rc=%d)\n", 46707fe6a43SSeth Howell base_bdev_name, rc); 46807fe6a43SSeth Howell } 46907fe6a43SSeth Howell 47007fe6a43SSeth Howell return rc; 47107fe6a43SSeth Howell } 47207fe6a43SSeth Howell 47307fe6a43SSeth Howell void 4744573e4ccSShuhei Matsumoto vbdev_error_delete(const char *error_vbdev_name, spdk_delete_error_complete cb_fn, void *cb_arg) 47507fe6a43SSeth Howell { 4764573e4ccSShuhei Matsumoto int rc; 47707fe6a43SSeth Howell 4784573e4ccSShuhei Matsumoto rc = spdk_bdev_unregister_by_name(error_vbdev_name, &error_if, cb_fn, cb_arg); 4794573e4ccSShuhei Matsumoto if (rc != 0) { 4804573e4ccSShuhei Matsumoto cb_fn(cb_arg, rc); 4814573e4ccSShuhei Matsumoto } 48207fe6a43SSeth Howell } 48307fe6a43SSeth Howell 48407fe6a43SSeth Howell static void 48507fe6a43SSeth Howell vbdev_error_clear_config(void) 48607fe6a43SSeth Howell { 48707fe6a43SSeth Howell struct spdk_vbdev_error_config *cfg; 48807fe6a43SSeth Howell 48907fe6a43SSeth Howell while ((cfg = TAILQ_FIRST(&g_error_config))) { 49007fe6a43SSeth Howell TAILQ_REMOVE(&g_error_config, cfg, tailq); 49107fe6a43SSeth Howell free(cfg->base_bdev); 49207fe6a43SSeth Howell free(cfg); 49307fe6a43SSeth Howell } 49407fe6a43SSeth Howell } 49507fe6a43SSeth Howell 49607fe6a43SSeth Howell static struct spdk_vbdev_error_config * 49707fe6a43SSeth Howell vbdev_error_config_find_by_base_name(const char *base_bdev_name) 49807fe6a43SSeth Howell { 49907fe6a43SSeth Howell struct spdk_vbdev_error_config *cfg; 50007fe6a43SSeth Howell 50107fe6a43SSeth Howell TAILQ_FOREACH(cfg, &g_error_config, tailq) { 50207fe6a43SSeth Howell if (strcmp(cfg->base_bdev, base_bdev_name) == 0) { 50307fe6a43SSeth Howell return cfg; 50407fe6a43SSeth Howell } 50507fe6a43SSeth Howell } 50607fe6a43SSeth Howell 50707fe6a43SSeth Howell return NULL; 50807fe6a43SSeth Howell } 50907fe6a43SSeth Howell 51007fe6a43SSeth Howell static int 51191ea8102SKrzysztof Karas vbdev_error_config_add(const char *base_bdev_name, const struct spdk_uuid *uuid) 51207fe6a43SSeth Howell { 51307fe6a43SSeth Howell struct spdk_vbdev_error_config *cfg; 51407fe6a43SSeth Howell 51507fe6a43SSeth Howell cfg = vbdev_error_config_find_by_base_name(base_bdev_name); 51607fe6a43SSeth Howell if (cfg) { 51707fe6a43SSeth Howell SPDK_ERRLOG("vbdev_error_config for bdev %s already exists\n", 51807fe6a43SSeth Howell base_bdev_name); 51907fe6a43SSeth Howell return -EEXIST; 52007fe6a43SSeth Howell } 52107fe6a43SSeth Howell 52207fe6a43SSeth Howell cfg = calloc(1, sizeof(*cfg)); 52307fe6a43SSeth Howell if (!cfg) { 52407fe6a43SSeth Howell SPDK_ERRLOG("calloc() failed for vbdev_error_config\n"); 52507fe6a43SSeth Howell return -ENOMEM; 52607fe6a43SSeth Howell } 52707fe6a43SSeth Howell 52807fe6a43SSeth Howell cfg->base_bdev = strdup(base_bdev_name); 52907fe6a43SSeth Howell if (!cfg->base_bdev) { 53007fe6a43SSeth Howell free(cfg); 53107fe6a43SSeth Howell SPDK_ERRLOG("strdup() failed for base_bdev_name\n"); 53207fe6a43SSeth Howell return -ENOMEM; 53307fe6a43SSeth Howell } 53407fe6a43SSeth Howell 53591ea8102SKrzysztof Karas spdk_uuid_copy(&cfg->uuid, uuid); 53607fe6a43SSeth Howell TAILQ_INSERT_TAIL(&g_error_config, cfg, tailq); 53707fe6a43SSeth Howell 53807fe6a43SSeth Howell return 0; 53907fe6a43SSeth Howell } 54007fe6a43SSeth Howell 54107fe6a43SSeth Howell static int 54207fe6a43SSeth Howell vbdev_error_config_remove(const char *base_bdev_name) 54307fe6a43SSeth Howell { 54407fe6a43SSeth Howell struct spdk_vbdev_error_config *cfg; 54507fe6a43SSeth Howell 54607fe6a43SSeth Howell cfg = vbdev_error_config_find_by_base_name(base_bdev_name); 54707fe6a43SSeth Howell if (!cfg) { 54807fe6a43SSeth Howell return -ENOENT; 54907fe6a43SSeth Howell } 55007fe6a43SSeth Howell 55107fe6a43SSeth Howell TAILQ_REMOVE(&g_error_config, cfg, tailq); 55207fe6a43SSeth Howell free(cfg->base_bdev); 55307fe6a43SSeth Howell free(cfg); 55407fe6a43SSeth Howell return 0; 55507fe6a43SSeth Howell } 55607fe6a43SSeth Howell 55707fe6a43SSeth Howell static int 55807fe6a43SSeth Howell vbdev_error_init(void) 55907fe6a43SSeth Howell { 56007fe6a43SSeth Howell return 0; 56107fe6a43SSeth Howell } 56207fe6a43SSeth Howell 56307fe6a43SSeth Howell static void 56407fe6a43SSeth Howell vbdev_error_fini(void) 56507fe6a43SSeth Howell { 56607fe6a43SSeth Howell vbdev_error_clear_config(); 56707fe6a43SSeth Howell } 56807fe6a43SSeth Howell 56907fe6a43SSeth Howell static void 57007fe6a43SSeth Howell vbdev_error_examine(struct spdk_bdev *bdev) 57107fe6a43SSeth Howell { 57207fe6a43SSeth Howell struct spdk_vbdev_error_config *cfg; 57307fe6a43SSeth Howell int rc; 57407fe6a43SSeth Howell 57507fe6a43SSeth Howell cfg = vbdev_error_config_find_by_base_name(bdev->name); 57607fe6a43SSeth Howell if (cfg != NULL) { 57791ea8102SKrzysztof Karas rc = _vbdev_error_create(bdev->name, &cfg->uuid); 57807fe6a43SSeth Howell if (rc != 0) { 57907fe6a43SSeth Howell SPDK_ERRLOG("could not create error vbdev for bdev %s at examine\n", 58007fe6a43SSeth Howell bdev->name); 58107fe6a43SSeth Howell } 58207fe6a43SSeth Howell } 58307fe6a43SSeth Howell 58407fe6a43SSeth Howell spdk_bdev_module_examine_done(&error_if); 58507fe6a43SSeth Howell } 58607fe6a43SSeth Howell 58707fe6a43SSeth Howell static int 58807fe6a43SSeth Howell vbdev_error_config_json(struct spdk_json_write_ctx *w) 58907fe6a43SSeth Howell { 59007fe6a43SSeth Howell struct spdk_vbdev_error_config *cfg; 59107fe6a43SSeth Howell 59207fe6a43SSeth Howell TAILQ_FOREACH(cfg, &g_error_config, tailq) { 59307fe6a43SSeth Howell spdk_json_write_object_begin(w); 59407fe6a43SSeth Howell 595cabb6a7dSMaciej Wawryk spdk_json_write_named_string(w, "method", "bdev_error_create"); 59607fe6a43SSeth Howell spdk_json_write_named_object_begin(w, "params"); 59707fe6a43SSeth Howell spdk_json_write_named_string(w, "base_name", cfg->base_bdev); 5986649e6ceSArtur Paszkiewicz if (!spdk_uuid_is_null(&cfg->uuid)) { 59969f9c9acSJim Harris spdk_json_write_named_uuid(w, "uuid", &cfg->uuid); 60091ea8102SKrzysztof Karas } 60107fe6a43SSeth Howell spdk_json_write_object_end(w); 60207fe6a43SSeth Howell 60307fe6a43SSeth Howell spdk_json_write_object_end(w); 60407fe6a43SSeth Howell } 60507fe6a43SSeth Howell 60607fe6a43SSeth Howell return 0; 60707fe6a43SSeth Howell } 608