1488570ebSJim Harris /* SPDX-License-Identifier: BSD-3-Clause 2a6dbe372Spaul luse * Copyright (C) 2018 Intel Corporation. 307fe6a43SSeth Howell * All rights reserved. 4be440c01SAlexey Marchuk * Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. 507fe6a43SSeth Howell */ 607fe6a43SSeth Howell 707fe6a43SSeth Howell #include "bdev_raid.h" 807fe6a43SSeth Howell #include "spdk/env.h" 98e05b15cSDarek Stojaczyk #include "spdk/thread.h" 104e8e97c8STomasz Zawadzki #include "spdk/log.h" 1107fe6a43SSeth Howell #include "spdk/string.h" 1207fe6a43SSeth Howell #include "spdk/util.h" 1307fe6a43SSeth Howell #include "spdk/json.h" 142b867a50SArtur Paszkiewicz #include "spdk/likely.h" 158d52c4c2Sxupeng-mingtu #include "spdk/trace.h" 168d52c4c2Sxupeng-mingtu #include "spdk_internal/trace_defs.h" 1707fe6a43SSeth Howell 1850d58ff3SArtur Paszkiewicz #define RAID_OFFSET_BLOCKS_INVALID UINT64_MAX 1950d58ff3SArtur Paszkiewicz #define RAID_BDEV_PROCESS_MAX_QD 16 2050d58ff3SArtur Paszkiewicz 21f39350beSArtur Paszkiewicz #define RAID_BDEV_PROCESS_WINDOW_SIZE_KB_DEFAULT 1024 2289fd1730Sxupeng9 #define RAID_BDEV_PROCESS_MAX_BANDWIDTH_MB_SEC_DEFAULT 0 23f39350beSArtur Paszkiewicz 2407fe6a43SSeth Howell static bool g_shutdown_started = false; 2507fe6a43SSeth Howell 2607fe6a43SSeth Howell /* List of all raid bdevs */ 2707fe6a43SSeth Howell struct raid_all_tailq g_raid_bdev_list = TAILQ_HEAD_INITIALIZER(g_raid_bdev_list); 2807fe6a43SSeth Howell 29706029d5SArtur Paszkiewicz static TAILQ_HEAD(, raid_bdev_module) g_raid_modules = TAILQ_HEAD_INITIALIZER(g_raid_modules); 30706029d5SArtur Paszkiewicz 316e03e49bSArtur Paszkiewicz /* 326e03e49bSArtur Paszkiewicz * raid_bdev_io_channel is the context of spdk_io_channel for raid bdev device. It 336e03e49bSArtur Paszkiewicz * contains the relationship of raid bdev io channel with base bdev io channels. 346e03e49bSArtur Paszkiewicz */ 356e03e49bSArtur Paszkiewicz struct raid_bdev_io_channel { 366e03e49bSArtur Paszkiewicz /* Array of IO channels of base bdevs */ 376e03e49bSArtur Paszkiewicz struct spdk_io_channel **base_channel; 386e03e49bSArtur Paszkiewicz 396e03e49bSArtur Paszkiewicz /* Private raid module IO channel */ 406e03e49bSArtur Paszkiewicz struct spdk_io_channel *module_channel; 4150d58ff3SArtur Paszkiewicz 4250d58ff3SArtur Paszkiewicz /* Background process data */ 4350d58ff3SArtur Paszkiewicz struct { 4450d58ff3SArtur Paszkiewicz uint64_t offset; 4550d58ff3SArtur Paszkiewicz struct spdk_io_channel *target_ch; 46aae5e04fSArtur Paszkiewicz struct raid_bdev_io_channel *ch_processed; 4750d58ff3SArtur Paszkiewicz } process; 4850d58ff3SArtur Paszkiewicz }; 4950d58ff3SArtur Paszkiewicz 5050d58ff3SArtur Paszkiewicz enum raid_bdev_process_state { 5150d58ff3SArtur Paszkiewicz RAID_PROCESS_STATE_INIT, 5250d58ff3SArtur Paszkiewicz RAID_PROCESS_STATE_RUNNING, 5350d58ff3SArtur Paszkiewicz RAID_PROCESS_STATE_STOPPING, 5450d58ff3SArtur Paszkiewicz RAID_PROCESS_STATE_STOPPED, 5550d58ff3SArtur Paszkiewicz }; 5650d58ff3SArtur Paszkiewicz 5789fd1730Sxupeng9 struct raid_process_qos { 5889fd1730Sxupeng9 bool enable_qos; 5989fd1730Sxupeng9 uint64_t last_tsc; 6089fd1730Sxupeng9 double bytes_per_tsc; 6189fd1730Sxupeng9 double bytes_available; 6289fd1730Sxupeng9 double bytes_max; 6389fd1730Sxupeng9 struct spdk_poller *process_continue_poller; 6489fd1730Sxupeng9 }; 6589fd1730Sxupeng9 6650d58ff3SArtur Paszkiewicz struct raid_bdev_process { 6750d58ff3SArtur Paszkiewicz struct raid_bdev *raid_bdev; 6850d58ff3SArtur Paszkiewicz enum raid_process_type type; 6950d58ff3SArtur Paszkiewicz enum raid_bdev_process_state state; 7050d58ff3SArtur Paszkiewicz struct spdk_thread *thread; 7150d58ff3SArtur Paszkiewicz struct raid_bdev_io_channel *raid_ch; 7250d58ff3SArtur Paszkiewicz TAILQ_HEAD(, raid_bdev_process_request) requests; 7350d58ff3SArtur Paszkiewicz uint64_t max_window_size; 7450d58ff3SArtur Paszkiewicz uint64_t window_size; 7550d58ff3SArtur Paszkiewicz uint64_t window_remaining; 7650d58ff3SArtur Paszkiewicz int window_status; 7750d58ff3SArtur Paszkiewicz uint64_t window_offset; 7850d58ff3SArtur Paszkiewicz bool window_range_locked; 7950d58ff3SArtur Paszkiewicz struct raid_base_bdev_info *target; 8050d58ff3SArtur Paszkiewicz int status; 819d2b7b41SArtur Paszkiewicz TAILQ_HEAD(, raid_process_finish_action) finish_actions; 8289fd1730Sxupeng9 struct raid_process_qos qos; 839d2b7b41SArtur Paszkiewicz }; 849d2b7b41SArtur Paszkiewicz 859d2b7b41SArtur Paszkiewicz struct raid_process_finish_action { 869d2b7b41SArtur Paszkiewicz spdk_msg_fn cb; 879d2b7b41SArtur Paszkiewicz void *cb_ctx; 889d2b7b41SArtur Paszkiewicz TAILQ_ENTRY(raid_process_finish_action) link; 896e03e49bSArtur Paszkiewicz }; 906e03e49bSArtur Paszkiewicz 91f39350beSArtur Paszkiewicz static struct spdk_raid_bdev_opts g_opts = { 92f39350beSArtur Paszkiewicz .process_window_size_kb = RAID_BDEV_PROCESS_WINDOW_SIZE_KB_DEFAULT, 9389fd1730Sxupeng9 .process_max_bandwidth_mb_sec = RAID_BDEV_PROCESS_MAX_BANDWIDTH_MB_SEC_DEFAULT, 94f39350beSArtur Paszkiewicz }; 95f39350beSArtur Paszkiewicz 96f39350beSArtur Paszkiewicz void 97f39350beSArtur Paszkiewicz raid_bdev_get_opts(struct spdk_raid_bdev_opts *opts) 98f39350beSArtur Paszkiewicz { 99f39350beSArtur Paszkiewicz *opts = g_opts; 100f39350beSArtur Paszkiewicz } 101f39350beSArtur Paszkiewicz 102f39350beSArtur Paszkiewicz int 103f39350beSArtur Paszkiewicz raid_bdev_set_opts(const struct spdk_raid_bdev_opts *opts) 104f39350beSArtur Paszkiewicz { 105f39350beSArtur Paszkiewicz if (opts->process_window_size_kb == 0) { 106f39350beSArtur Paszkiewicz return -EINVAL; 107f39350beSArtur Paszkiewicz } 108f39350beSArtur Paszkiewicz 109f39350beSArtur Paszkiewicz g_opts = *opts; 110f39350beSArtur Paszkiewicz 111f39350beSArtur Paszkiewicz return 0; 112f39350beSArtur Paszkiewicz } 113f39350beSArtur Paszkiewicz 1148dd1cd21SBen Walker static struct raid_bdev_module * 1158dd1cd21SBen Walker raid_bdev_module_find(enum raid_level level) 116706029d5SArtur Paszkiewicz { 117706029d5SArtur Paszkiewicz struct raid_bdev_module *raid_module; 118706029d5SArtur Paszkiewicz 119706029d5SArtur Paszkiewicz TAILQ_FOREACH(raid_module, &g_raid_modules, link) { 120706029d5SArtur Paszkiewicz if (raid_module->level == level) { 121706029d5SArtur Paszkiewicz return raid_module; 122706029d5SArtur Paszkiewicz } 123706029d5SArtur Paszkiewicz } 124706029d5SArtur Paszkiewicz 125706029d5SArtur Paszkiewicz return NULL; 126706029d5SArtur Paszkiewicz } 127706029d5SArtur Paszkiewicz 1288dd1cd21SBen Walker void 1298dd1cd21SBen Walker raid_bdev_module_list_add(struct raid_bdev_module *raid_module) 130706029d5SArtur Paszkiewicz { 131706029d5SArtur Paszkiewicz if (raid_bdev_module_find(raid_module->level) != NULL) { 132706029d5SArtur Paszkiewicz SPDK_ERRLOG("module for raid level '%s' already registered.\n", 133706029d5SArtur Paszkiewicz raid_bdev_level_to_str(raid_module->level)); 134706029d5SArtur Paszkiewicz assert(false); 135706029d5SArtur Paszkiewicz } else { 136706029d5SArtur Paszkiewicz TAILQ_INSERT_TAIL(&g_raid_modules, raid_module, link); 137706029d5SArtur Paszkiewicz } 138706029d5SArtur Paszkiewicz } 139706029d5SArtur Paszkiewicz 1406e03e49bSArtur Paszkiewicz struct spdk_io_channel * 1416e03e49bSArtur Paszkiewicz raid_bdev_channel_get_base_channel(struct raid_bdev_io_channel *raid_ch, uint8_t idx) 1426e03e49bSArtur Paszkiewicz { 1436e03e49bSArtur Paszkiewicz return raid_ch->base_channel[idx]; 1446e03e49bSArtur Paszkiewicz } 1456e03e49bSArtur Paszkiewicz 1466e03e49bSArtur Paszkiewicz void * 1476e03e49bSArtur Paszkiewicz raid_bdev_channel_get_module_ctx(struct raid_bdev_io_channel *raid_ch) 1486e03e49bSArtur Paszkiewicz { 1496e03e49bSArtur Paszkiewicz assert(raid_ch->module_channel != NULL); 1506e03e49bSArtur Paszkiewicz 1516e03e49bSArtur Paszkiewicz return spdk_io_channel_get_ctx(raid_ch->module_channel); 1526e03e49bSArtur Paszkiewicz } 1536e03e49bSArtur Paszkiewicz 15435a054dbSArtur Paszkiewicz struct raid_base_bdev_info * 15535a054dbSArtur Paszkiewicz raid_bdev_channel_get_base_info(struct raid_bdev_io_channel *raid_ch, struct spdk_bdev *base_bdev) 15635a054dbSArtur Paszkiewicz { 15735a054dbSArtur Paszkiewicz struct spdk_io_channel *ch = spdk_io_channel_from_ctx(raid_ch); 15835a054dbSArtur Paszkiewicz struct raid_bdev *raid_bdev = spdk_io_channel_get_io_device(ch); 15935a054dbSArtur Paszkiewicz uint8_t i; 16035a054dbSArtur Paszkiewicz 16135a054dbSArtur Paszkiewicz for (i = 0; i < raid_bdev->num_base_bdevs; i++) { 16235a054dbSArtur Paszkiewicz struct raid_base_bdev_info *base_info = &raid_bdev->base_bdev_info[i]; 16335a054dbSArtur Paszkiewicz 16435a054dbSArtur Paszkiewicz if (base_info->is_configured && 16535a054dbSArtur Paszkiewicz spdk_bdev_desc_get_bdev(base_info->desc) == base_bdev) { 16635a054dbSArtur Paszkiewicz return base_info; 16735a054dbSArtur Paszkiewicz } 16835a054dbSArtur Paszkiewicz } 16935a054dbSArtur Paszkiewicz 17035a054dbSArtur Paszkiewicz return NULL; 17135a054dbSArtur Paszkiewicz } 17235a054dbSArtur Paszkiewicz 17307fe6a43SSeth Howell /* Function declarations */ 17407fe6a43SSeth Howell static void raid_bdev_examine(struct spdk_bdev *bdev); 17507fe6a43SSeth Howell static int raid_bdev_init(void); 17607fe6a43SSeth Howell static void raid_bdev_deconfigure(struct raid_bdev *raid_bdev, 17707fe6a43SSeth Howell raid_bdev_destruct_cb cb_fn, void *cb_arg); 17807fe6a43SSeth Howell 17950d58ff3SArtur Paszkiewicz static void 18050d58ff3SArtur Paszkiewicz raid_bdev_ch_process_cleanup(struct raid_bdev_io_channel *raid_ch) 18150d58ff3SArtur Paszkiewicz { 18250d58ff3SArtur Paszkiewicz raid_ch->process.offset = RAID_OFFSET_BLOCKS_INVALID; 18350d58ff3SArtur Paszkiewicz 18450d58ff3SArtur Paszkiewicz if (raid_ch->process.target_ch != NULL) { 18550d58ff3SArtur Paszkiewicz spdk_put_io_channel(raid_ch->process.target_ch); 18650d58ff3SArtur Paszkiewicz raid_ch->process.target_ch = NULL; 18750d58ff3SArtur Paszkiewicz } 188aae5e04fSArtur Paszkiewicz 189aae5e04fSArtur Paszkiewicz if (raid_ch->process.ch_processed != NULL) { 190aae5e04fSArtur Paszkiewicz free(raid_ch->process.ch_processed->base_channel); 191aae5e04fSArtur Paszkiewicz free(raid_ch->process.ch_processed); 192aae5e04fSArtur Paszkiewicz raid_ch->process.ch_processed = NULL; 193aae5e04fSArtur Paszkiewicz } 19450d58ff3SArtur Paszkiewicz } 19550d58ff3SArtur Paszkiewicz 19650d58ff3SArtur Paszkiewicz static int 19750d58ff3SArtur Paszkiewicz raid_bdev_ch_process_setup(struct raid_bdev_io_channel *raid_ch, struct raid_bdev_process *process) 19850d58ff3SArtur Paszkiewicz { 199aae5e04fSArtur Paszkiewicz struct raid_bdev *raid_bdev = process->raid_bdev; 200aae5e04fSArtur Paszkiewicz struct raid_bdev_io_channel *raid_ch_processed; 201aae5e04fSArtur Paszkiewicz struct raid_base_bdev_info *base_info; 202aae5e04fSArtur Paszkiewicz 20350d58ff3SArtur Paszkiewicz raid_ch->process.offset = process->window_offset; 20450d58ff3SArtur Paszkiewicz 20550d58ff3SArtur Paszkiewicz /* In the future we may have other types of processes which don't use a target bdev, 20650d58ff3SArtur Paszkiewicz * like data scrubbing or strip size migration. Until then, expect that there always is 20750d58ff3SArtur Paszkiewicz * a process target. */ 20850d58ff3SArtur Paszkiewicz assert(process->target != NULL); 20950d58ff3SArtur Paszkiewicz 21050d58ff3SArtur Paszkiewicz raid_ch->process.target_ch = spdk_bdev_get_io_channel(process->target->desc); 21150d58ff3SArtur Paszkiewicz if (raid_ch->process.target_ch == NULL) { 212aae5e04fSArtur Paszkiewicz goto err; 21350d58ff3SArtur Paszkiewicz } 21450d58ff3SArtur Paszkiewicz 215aae5e04fSArtur Paszkiewicz raid_ch_processed = calloc(1, sizeof(*raid_ch_processed)); 216aae5e04fSArtur Paszkiewicz if (raid_ch_processed == NULL) { 217aae5e04fSArtur Paszkiewicz goto err; 218aae5e04fSArtur Paszkiewicz } 219aae5e04fSArtur Paszkiewicz raid_ch->process.ch_processed = raid_ch_processed; 220aae5e04fSArtur Paszkiewicz 221aae5e04fSArtur Paszkiewicz raid_ch_processed->base_channel = calloc(raid_bdev->num_base_bdevs, 222aae5e04fSArtur Paszkiewicz sizeof(*raid_ch_processed->base_channel)); 223aae5e04fSArtur Paszkiewicz if (raid_ch_processed->base_channel == NULL) { 224aae5e04fSArtur Paszkiewicz goto err; 225aae5e04fSArtur Paszkiewicz } 226aae5e04fSArtur Paszkiewicz 227aae5e04fSArtur Paszkiewicz RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) { 228aae5e04fSArtur Paszkiewicz uint8_t slot = raid_bdev_base_bdev_slot(base_info); 229aae5e04fSArtur Paszkiewicz 230aae5e04fSArtur Paszkiewicz if (base_info != process->target) { 231aae5e04fSArtur Paszkiewicz raid_ch_processed->base_channel[slot] = raid_ch->base_channel[slot]; 232aae5e04fSArtur Paszkiewicz } else { 233aae5e04fSArtur Paszkiewicz raid_ch_processed->base_channel[slot] = raid_ch->process.target_ch; 234aae5e04fSArtur Paszkiewicz } 235aae5e04fSArtur Paszkiewicz } 236aae5e04fSArtur Paszkiewicz 237aae5e04fSArtur Paszkiewicz raid_ch_processed->module_channel = raid_ch->module_channel; 238aae5e04fSArtur Paszkiewicz raid_ch_processed->process.offset = RAID_OFFSET_BLOCKS_INVALID; 239aae5e04fSArtur Paszkiewicz 24050d58ff3SArtur Paszkiewicz return 0; 241aae5e04fSArtur Paszkiewicz err: 242aae5e04fSArtur Paszkiewicz raid_bdev_ch_process_cleanup(raid_ch); 243aae5e04fSArtur Paszkiewicz return -ENOMEM; 24450d58ff3SArtur Paszkiewicz } 24550d58ff3SArtur Paszkiewicz 24607fe6a43SSeth Howell /* 24707fe6a43SSeth Howell * brief: 24807fe6a43SSeth Howell * raid_bdev_create_cb function is a cb function for raid bdev which creates the 24907fe6a43SSeth Howell * hierarchy from raid bdev to base bdev io channels. It will be called per core 25007fe6a43SSeth Howell * params: 25107fe6a43SSeth Howell * io_device - pointer to raid bdev io device represented by raid_bdev 25207fe6a43SSeth Howell * ctx_buf - pointer to context buffer for raid bdev io channel 25307fe6a43SSeth Howell * returns: 25407fe6a43SSeth Howell * 0 - success 25507fe6a43SSeth Howell * non zero - failure 25607fe6a43SSeth Howell */ 25707fe6a43SSeth Howell static int 25807fe6a43SSeth Howell raid_bdev_create_cb(void *io_device, void *ctx_buf) 25907fe6a43SSeth Howell { 26007fe6a43SSeth Howell struct raid_bdev *raid_bdev = io_device; 26107fe6a43SSeth Howell struct raid_bdev_io_channel *raid_ch = ctx_buf; 2629d94e1f5SArtur Paszkiewicz uint8_t i; 26350d58ff3SArtur Paszkiewicz int ret = -ENOMEM; 26407fe6a43SSeth Howell 2652172c432STomasz Zawadzki SPDK_DEBUGLOG(bdev_raid, "raid_bdev_create_cb, %p\n", raid_ch); 26607fe6a43SSeth Howell 26707fe6a43SSeth Howell assert(raid_bdev != NULL); 26807fe6a43SSeth Howell assert(raid_bdev->state == RAID_BDEV_STATE_ONLINE); 26907fe6a43SSeth Howell 270030dab89SArtur Paszkiewicz raid_ch->base_channel = calloc(raid_bdev->num_base_bdevs, sizeof(struct spdk_io_channel *)); 27107fe6a43SSeth Howell if (!raid_ch->base_channel) { 27207fe6a43SSeth Howell SPDK_ERRLOG("Unable to allocate base bdevs io channel\n"); 27307fe6a43SSeth Howell return -ENOMEM; 27407fe6a43SSeth Howell } 275b42cb0e5SArtur Paszkiewicz 276030dab89SArtur Paszkiewicz for (i = 0; i < raid_bdev->num_base_bdevs; i++) { 27707fe6a43SSeth Howell /* 27807fe6a43SSeth Howell * Get the spdk_io_channel for all the base bdevs. This is used during 27907fe6a43SSeth Howell * split logic to send the respective child bdev ios to respective base 28007fe6a43SSeth Howell * bdev io channel. 28150d58ff3SArtur Paszkiewicz * Skip missing base bdevs and the process target, which should also be treated as 28250d58ff3SArtur Paszkiewicz * missing until the process completes. 28307fe6a43SSeth Howell */ 2846518a98dSArtur Paszkiewicz if (raid_bdev->base_bdev_info[i].is_configured == false || 285a6708553SArtur Paszkiewicz raid_bdev->base_bdev_info[i].is_process_target == true) { 286b42cb0e5SArtur Paszkiewicz continue; 287b42cb0e5SArtur Paszkiewicz } 28807fe6a43SSeth Howell raid_ch->base_channel[i] = spdk_bdev_get_io_channel( 28907fe6a43SSeth Howell raid_bdev->base_bdev_info[i].desc); 29007fe6a43SSeth Howell if (!raid_ch->base_channel[i]) { 291c89e2008SArtur Paszkiewicz SPDK_ERRLOG("Unable to create io channel for base bdev\n"); 29250d58ff3SArtur Paszkiewicz goto err; 293c89e2008SArtur Paszkiewicz } 294c89e2008SArtur Paszkiewicz } 29550d58ff3SArtur Paszkiewicz 29651978c16SArtur Paszkiewicz if (raid_bdev->module->get_io_channel) { 29751978c16SArtur Paszkiewicz raid_ch->module_channel = raid_bdev->module->get_io_channel(raid_bdev); 29851978c16SArtur Paszkiewicz if (!raid_ch->module_channel) { 29951978c16SArtur Paszkiewicz SPDK_ERRLOG("Unable to create io channel for raid module\n"); 30051978c16SArtur Paszkiewicz goto err; 30151978c16SArtur Paszkiewicz } 30251978c16SArtur Paszkiewicz } 30351978c16SArtur Paszkiewicz 30450d58ff3SArtur Paszkiewicz if (raid_bdev->process != NULL) { 30550d58ff3SArtur Paszkiewicz ret = raid_bdev_ch_process_setup(raid_ch, raid_bdev->process); 30650d58ff3SArtur Paszkiewicz if (ret != 0) { 30750d58ff3SArtur Paszkiewicz SPDK_ERRLOG("Failed to setup process io channel\n"); 30850d58ff3SArtur Paszkiewicz goto err; 30950d58ff3SArtur Paszkiewicz } 31050d58ff3SArtur Paszkiewicz } else { 31150d58ff3SArtur Paszkiewicz raid_ch->process.offset = RAID_OFFSET_BLOCKS_INVALID; 31250d58ff3SArtur Paszkiewicz } 313c89e2008SArtur Paszkiewicz 31450d58ff3SArtur Paszkiewicz return 0; 31550d58ff3SArtur Paszkiewicz err: 316030dab89SArtur Paszkiewicz for (i = 0; i < raid_bdev->num_base_bdevs; i++) { 317b42cb0e5SArtur Paszkiewicz if (raid_ch->base_channel[i] != NULL) { 318b42cb0e5SArtur Paszkiewicz spdk_put_io_channel(raid_ch->base_channel[i]); 319b42cb0e5SArtur Paszkiewicz } 32007fe6a43SSeth Howell } 32107fe6a43SSeth Howell free(raid_ch->base_channel); 32250d58ff3SArtur Paszkiewicz 32350d58ff3SArtur Paszkiewicz raid_bdev_ch_process_cleanup(raid_ch); 32450d58ff3SArtur Paszkiewicz 325c89e2008SArtur Paszkiewicz return ret; 32607fe6a43SSeth Howell } 32707fe6a43SSeth Howell 32807fe6a43SSeth Howell /* 32907fe6a43SSeth Howell * brief: 33007fe6a43SSeth Howell * raid_bdev_destroy_cb function is a cb function for raid bdev which deletes the 33107fe6a43SSeth Howell * hierarchy from raid bdev to base bdev io channels. It will be called per core 33207fe6a43SSeth Howell * params: 33307fe6a43SSeth Howell * io_device - pointer to raid bdev io device represented by raid_bdev 33407fe6a43SSeth Howell * ctx_buf - pointer to context buffer for raid bdev io channel 33507fe6a43SSeth Howell * returns: 33607fe6a43SSeth Howell * none 33707fe6a43SSeth Howell */ 33807fe6a43SSeth Howell static void 33907fe6a43SSeth Howell raid_bdev_destroy_cb(void *io_device, void *ctx_buf) 34007fe6a43SSeth Howell { 341030dab89SArtur Paszkiewicz struct raid_bdev *raid_bdev = io_device; 34207fe6a43SSeth Howell struct raid_bdev_io_channel *raid_ch = ctx_buf; 3439d94e1f5SArtur Paszkiewicz uint8_t i; 34407fe6a43SSeth Howell 3452172c432STomasz Zawadzki SPDK_DEBUGLOG(bdev_raid, "raid_bdev_destroy_cb\n"); 34607fe6a43SSeth Howell 34707fe6a43SSeth Howell assert(raid_ch != NULL); 34807fe6a43SSeth Howell assert(raid_ch->base_channel); 349c89e2008SArtur Paszkiewicz 350c89e2008SArtur Paszkiewicz if (raid_ch->module_channel) { 351c89e2008SArtur Paszkiewicz spdk_put_io_channel(raid_ch->module_channel); 352c89e2008SArtur Paszkiewicz } 353c89e2008SArtur Paszkiewicz 354030dab89SArtur Paszkiewicz for (i = 0; i < raid_bdev->num_base_bdevs; i++) { 35507fe6a43SSeth Howell /* Free base bdev channels */ 356b42cb0e5SArtur Paszkiewicz if (raid_ch->base_channel[i] != NULL) { 35707fe6a43SSeth Howell spdk_put_io_channel(raid_ch->base_channel[i]); 35807fe6a43SSeth Howell } 359b42cb0e5SArtur Paszkiewicz } 36007fe6a43SSeth Howell free(raid_ch->base_channel); 36107fe6a43SSeth Howell raid_ch->base_channel = NULL; 36250d58ff3SArtur Paszkiewicz 36350d58ff3SArtur Paszkiewicz raid_bdev_ch_process_cleanup(raid_ch); 36407fe6a43SSeth Howell } 36507fe6a43SSeth Howell 36607fe6a43SSeth Howell /* 36707fe6a43SSeth Howell * brief: 36895a04949SArtur Paszkiewicz * raid_bdev_cleanup is used to cleanup raid_bdev related data 36907fe6a43SSeth Howell * structures. 37007fe6a43SSeth Howell * params: 37107fe6a43SSeth Howell * raid_bdev - pointer to raid_bdev 37207fe6a43SSeth Howell * returns: 37307fe6a43SSeth Howell * none 37407fe6a43SSeth Howell */ 37507fe6a43SSeth Howell static void 37607fe6a43SSeth Howell raid_bdev_cleanup(struct raid_bdev *raid_bdev) 37707fe6a43SSeth Howell { 378dccdd1e5SArtur Paszkiewicz struct raid_base_bdev_info *base_info; 379dccdd1e5SArtur Paszkiewicz 38046ff15a6SArtur Paszkiewicz SPDK_DEBUGLOG(bdev_raid, "raid_bdev_cleanup, %p name %s, state %s\n", 38146ff15a6SArtur Paszkiewicz raid_bdev, raid_bdev->bdev.name, raid_bdev_state_to_str(raid_bdev->state)); 38212ed89acSArtur Paszkiewicz assert(raid_bdev->state != RAID_BDEV_STATE_ONLINE); 3834dd2a0d3SArtur Paszkiewicz assert(spdk_get_thread() == spdk_thread_get_app_thread()); 384dccdd1e5SArtur Paszkiewicz 385dccdd1e5SArtur Paszkiewicz RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) { 386dccdd1e5SArtur Paszkiewicz assert(base_info->desc == NULL); 387dccdd1e5SArtur Paszkiewicz free(base_info->name); 388dccdd1e5SArtur Paszkiewicz } 389dccdd1e5SArtur Paszkiewicz 39007fe6a43SSeth Howell TAILQ_REMOVE(&g_raid_bdev_list, raid_bdev, global_link); 39195a04949SArtur Paszkiewicz } 39295a04949SArtur Paszkiewicz 39395a04949SArtur Paszkiewicz static void 39495a04949SArtur Paszkiewicz raid_bdev_free(struct raid_bdev *raid_bdev) 39595a04949SArtur Paszkiewicz { 396c25b80e2SArtur Paszkiewicz raid_bdev_free_superblock(raid_bdev); 397fbdb05f0SArtur Paszkiewicz free(raid_bdev->base_bdev_info); 39895a04949SArtur Paszkiewicz free(raid_bdev->bdev.name); 39907fe6a43SSeth Howell free(raid_bdev); 40007fe6a43SSeth Howell } 40107fe6a43SSeth Howell 40295a04949SArtur Paszkiewicz static void 40395a04949SArtur Paszkiewicz raid_bdev_cleanup_and_free(struct raid_bdev *raid_bdev) 40495a04949SArtur Paszkiewicz { 40595a04949SArtur Paszkiewicz raid_bdev_cleanup(raid_bdev); 40695a04949SArtur Paszkiewicz raid_bdev_free(raid_bdev); 40795a04949SArtur Paszkiewicz } 40895a04949SArtur Paszkiewicz 4096518a98dSArtur Paszkiewicz static void 4106518a98dSArtur Paszkiewicz raid_bdev_deconfigure_base_bdev(struct raid_base_bdev_info *base_info) 4116518a98dSArtur Paszkiewicz { 4126518a98dSArtur Paszkiewicz struct raid_bdev *raid_bdev = base_info->raid_bdev; 4136518a98dSArtur Paszkiewicz 4146518a98dSArtur Paszkiewicz assert(base_info->is_configured); 4156518a98dSArtur Paszkiewicz assert(raid_bdev->num_base_bdevs_discovered); 4166518a98dSArtur Paszkiewicz raid_bdev->num_base_bdevs_discovered--; 4176518a98dSArtur Paszkiewicz base_info->is_configured = false; 418a6708553SArtur Paszkiewicz base_info->is_process_target = false; 4196518a98dSArtur Paszkiewicz } 4206518a98dSArtur Paszkiewicz 42107fe6a43SSeth Howell /* 42207fe6a43SSeth Howell * brief: 42307fe6a43SSeth Howell * free resource of base bdev for raid bdev 42407fe6a43SSeth Howell * params: 425a193dcb8SArtur Paszkiewicz * base_info - raid base bdev info 42607fe6a43SSeth Howell * returns: 42777b8f7b6SArtur Paszkiewicz * none 42807fe6a43SSeth Howell */ 42907fe6a43SSeth Howell static void 43026861b70SArtur Paszkiewicz raid_bdev_free_base_bdev_resource(struct raid_base_bdev_info *base_info) 43107fe6a43SSeth Howell { 43226861b70SArtur Paszkiewicz struct raid_bdev *raid_bdev = base_info->raid_bdev; 43326861b70SArtur Paszkiewicz 4344dd2a0d3SArtur Paszkiewicz assert(spdk_get_thread() == spdk_thread_get_app_thread()); 435fc2398dfSArtur Paszkiewicz assert(base_info->configure_cb == NULL); 4364dd2a0d3SArtur Paszkiewicz 437dccdd1e5SArtur Paszkiewicz free(base_info->name); 438dccdd1e5SArtur Paszkiewicz base_info->name = NULL; 4398a6bb6a8SArtur Paszkiewicz if (raid_bdev->state != RAID_BDEV_STATE_CONFIGURING) { 4408a6bb6a8SArtur Paszkiewicz spdk_uuid_set_null(&base_info->uuid); 4418a6bb6a8SArtur Paszkiewicz } 442f1a03e33SArtur Paszkiewicz base_info->is_failed = false; 443dccdd1e5SArtur Paszkiewicz 4443cd7b237SSebastian Brzezinka /* clear `data_offset` to allow it to be recalculated during configuration */ 4453cd7b237SSebastian Brzezinka base_info->data_offset = 0; 4463cd7b237SSebastian Brzezinka 4478d1993a5SArtur Paszkiewicz if (base_info->desc == NULL) { 448dccdd1e5SArtur Paszkiewicz return; 449dccdd1e5SArtur Paszkiewicz } 450dccdd1e5SArtur Paszkiewicz 4518d1993a5SArtur Paszkiewicz spdk_bdev_module_release_bdev(spdk_bdev_desc_get_bdev(base_info->desc)); 452a193dcb8SArtur Paszkiewicz spdk_bdev_close(base_info->desc); 453a193dcb8SArtur Paszkiewicz base_info->desc = NULL; 45477b8f7b6SArtur Paszkiewicz spdk_put_io_channel(base_info->app_thread_ch); 45577b8f7b6SArtur Paszkiewicz base_info->app_thread_ch = NULL; 45607fe6a43SSeth Howell 4579222ff97SArtur Paszkiewicz if (base_info->is_configured) { 4586518a98dSArtur Paszkiewicz raid_bdev_deconfigure_base_bdev(base_info); 4599222ff97SArtur Paszkiewicz } 46007fe6a43SSeth Howell } 46107fe6a43SSeth Howell 46295a04949SArtur Paszkiewicz static void 46395a04949SArtur Paszkiewicz raid_bdev_io_device_unregister_cb(void *io_device) 46495a04949SArtur Paszkiewicz { 46595a04949SArtur Paszkiewicz struct raid_bdev *raid_bdev = io_device; 46695a04949SArtur Paszkiewicz 46795a04949SArtur Paszkiewicz if (raid_bdev->num_base_bdevs_discovered == 0) { 46895a04949SArtur Paszkiewicz /* Free raid_bdev when there are no base bdevs left */ 46995a04949SArtur Paszkiewicz SPDK_DEBUGLOG(bdev_raid, "raid bdev base bdevs is 0, going to free all in destruct\n"); 47095a04949SArtur Paszkiewicz raid_bdev_cleanup(raid_bdev); 47195a04949SArtur Paszkiewicz spdk_bdev_destruct_done(&raid_bdev->bdev, 0); 47295a04949SArtur Paszkiewicz raid_bdev_free(raid_bdev); 47395a04949SArtur Paszkiewicz } else { 47495a04949SArtur Paszkiewicz spdk_bdev_destruct_done(&raid_bdev->bdev, 0); 47595a04949SArtur Paszkiewicz } 47695a04949SArtur Paszkiewicz } 47795a04949SArtur Paszkiewicz 4789cf1ab5bSArtur Paszkiewicz void 4799cf1ab5bSArtur Paszkiewicz raid_bdev_module_stop_done(struct raid_bdev *raid_bdev) 4809cf1ab5bSArtur Paszkiewicz { 4819cf1ab5bSArtur Paszkiewicz if (raid_bdev->state != RAID_BDEV_STATE_CONFIGURING) { 4829cf1ab5bSArtur Paszkiewicz spdk_io_device_unregister(raid_bdev, raid_bdev_io_device_unregister_cb); 4839cf1ab5bSArtur Paszkiewicz } 4849cf1ab5bSArtur Paszkiewicz } 4859cf1ab5bSArtur Paszkiewicz 4864dd2a0d3SArtur Paszkiewicz static void 4874dd2a0d3SArtur Paszkiewicz _raid_bdev_destruct(void *ctxt) 48807fe6a43SSeth Howell { 48907fe6a43SSeth Howell struct raid_bdev *raid_bdev = ctxt; 490a193dcb8SArtur Paszkiewicz struct raid_base_bdev_info *base_info; 49107fe6a43SSeth Howell 4922172c432STomasz Zawadzki SPDK_DEBUGLOG(bdev_raid, "raid_bdev_destruct\n"); 49307fe6a43SSeth Howell 4949d2b7b41SArtur Paszkiewicz assert(raid_bdev->process == NULL); 4959d2b7b41SArtur Paszkiewicz 496a193dcb8SArtur Paszkiewicz RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) { 49707fe6a43SSeth Howell /* 49807fe6a43SSeth Howell * Close all base bdev descriptors for which call has come from below 49907fe6a43SSeth Howell * layers. Also close the descriptors if we have started shutdown. 50007fe6a43SSeth Howell */ 501dccdd1e5SArtur Paszkiewicz if (g_shutdown_started || base_info->remove_scheduled == true) { 50226861b70SArtur Paszkiewicz raid_bdev_free_base_bdev_resource(base_info); 50307fe6a43SSeth Howell } 50407fe6a43SSeth Howell } 50507fe6a43SSeth Howell 50607fe6a43SSeth Howell if (g_shutdown_started) { 50707fe6a43SSeth Howell raid_bdev->state = RAID_BDEV_STATE_OFFLINE; 50807fe6a43SSeth Howell } 50907fe6a43SSeth Howell 510df80e8ffSyupeng if (raid_bdev->module->stop != NULL) { 5119cf1ab5bSArtur Paszkiewicz if (raid_bdev->module->stop(raid_bdev) == false) { 5124dd2a0d3SArtur Paszkiewicz return; 5139cf1ab5bSArtur Paszkiewicz } 514df80e8ffSyupeng } 515df80e8ffSyupeng 5169cf1ab5bSArtur Paszkiewicz raid_bdev_module_stop_done(raid_bdev); 5174dd2a0d3SArtur Paszkiewicz } 5184dd2a0d3SArtur Paszkiewicz 5194dd2a0d3SArtur Paszkiewicz static int 5204dd2a0d3SArtur Paszkiewicz raid_bdev_destruct(void *ctx) 5214dd2a0d3SArtur Paszkiewicz { 5224dd2a0d3SArtur Paszkiewicz spdk_thread_exec_msg(spdk_thread_get_app_thread(), _raid_bdev_destruct, ctx); 52307fe6a43SSeth Howell 52495a04949SArtur Paszkiewicz return 1; 52507fe6a43SSeth Howell } 52607fe6a43SSeth Howell 5271b9c5629SArtur Paszkiewicz int 528192db8deSSlawomir Ptak raid_bdev_remap_dix_reftag(void *md_buf, uint64_t num_blocks, 529192db8deSSlawomir Ptak struct spdk_bdev *bdev, uint32_t remapped_offset) 530192db8deSSlawomir Ptak { 531192db8deSSlawomir Ptak struct spdk_dif_ctx dif_ctx; 532192db8deSSlawomir Ptak struct spdk_dif_error err_blk = {}; 533192db8deSSlawomir Ptak int rc; 534192db8deSSlawomir Ptak struct spdk_dif_ctx_init_ext_opts dif_opts; 535192db8deSSlawomir Ptak struct iovec md_iov = { 536192db8deSSlawomir Ptak .iov_base = md_buf, 537192db8deSSlawomir Ptak .iov_len = num_blocks * bdev->md_len, 538192db8deSSlawomir Ptak }; 539192db8deSSlawomir Ptak 540192db8deSSlawomir Ptak if (md_buf == NULL) { 541192db8deSSlawomir Ptak return 0; 542192db8deSSlawomir Ptak } 543192db8deSSlawomir Ptak 544192db8deSSlawomir Ptak dif_opts.size = SPDK_SIZEOF(&dif_opts, dif_pi_format); 545fcf59a6fSShuhei Matsumoto dif_opts.dif_pi_format = bdev->dif_pi_format; 546192db8deSSlawomir Ptak rc = spdk_dif_ctx_init(&dif_ctx, 547192db8deSSlawomir Ptak bdev->blocklen, bdev->md_len, bdev->md_interleave, 548192db8deSSlawomir Ptak bdev->dif_is_head_of_md, bdev->dif_type, 549192db8deSSlawomir Ptak SPDK_DIF_FLAGS_REFTAG_CHECK, 550192db8deSSlawomir Ptak 0, 0, 0, 0, 0, &dif_opts); 551192db8deSSlawomir Ptak if (rc != 0) { 552192db8deSSlawomir Ptak SPDK_ERRLOG("Initialization of DIF context failed\n"); 553192db8deSSlawomir Ptak return rc; 554192db8deSSlawomir Ptak } 555192db8deSSlawomir Ptak 556192db8deSSlawomir Ptak spdk_dif_ctx_set_remapped_init_ref_tag(&dif_ctx, remapped_offset); 557192db8deSSlawomir Ptak 558192db8deSSlawomir Ptak rc = spdk_dix_remap_ref_tag(&md_iov, num_blocks, &dif_ctx, &err_blk, false); 559192db8deSSlawomir Ptak if (rc != 0) { 560192db8deSSlawomir Ptak SPDK_ERRLOG("Remapping reference tag failed. type=%d, offset=%d" 561192db8deSSlawomir Ptak PRIu32 "\n", err_blk.err_type, err_blk.err_offset); 562192db8deSSlawomir Ptak } 563192db8deSSlawomir Ptak 564192db8deSSlawomir Ptak return rc; 565192db8deSSlawomir Ptak } 566192db8deSSlawomir Ptak 567192db8deSSlawomir Ptak int 568192db8deSSlawomir Ptak raid_bdev_verify_dix_reftag(struct iovec *iovs, int iovcnt, void *md_buf, 569192db8deSSlawomir Ptak uint64_t num_blocks, struct spdk_bdev *bdev, uint32_t offset_blocks) 570192db8deSSlawomir Ptak { 571192db8deSSlawomir Ptak struct spdk_dif_ctx dif_ctx; 572192db8deSSlawomir Ptak struct spdk_dif_error err_blk = {}; 573192db8deSSlawomir Ptak int rc; 574192db8deSSlawomir Ptak struct spdk_dif_ctx_init_ext_opts dif_opts; 575192db8deSSlawomir Ptak struct iovec md_iov = { 576192db8deSSlawomir Ptak .iov_base = md_buf, 577192db8deSSlawomir Ptak .iov_len = num_blocks * bdev->md_len, 578192db8deSSlawomir Ptak }; 579192db8deSSlawomir Ptak 580192db8deSSlawomir Ptak if (md_buf == NULL) { 581192db8deSSlawomir Ptak return 0; 582192db8deSSlawomir Ptak } 583192db8deSSlawomir Ptak 584192db8deSSlawomir Ptak dif_opts.size = SPDK_SIZEOF(&dif_opts, dif_pi_format); 585fcf59a6fSShuhei Matsumoto dif_opts.dif_pi_format = bdev->dif_pi_format; 586192db8deSSlawomir Ptak rc = spdk_dif_ctx_init(&dif_ctx, 587192db8deSSlawomir Ptak bdev->blocklen, bdev->md_len, bdev->md_interleave, 588192db8deSSlawomir Ptak bdev->dif_is_head_of_md, bdev->dif_type, 589192db8deSSlawomir Ptak SPDK_DIF_FLAGS_REFTAG_CHECK, 590192db8deSSlawomir Ptak offset_blocks, 0, 0, 0, 0, &dif_opts); 591192db8deSSlawomir Ptak if (rc != 0) { 592192db8deSSlawomir Ptak SPDK_ERRLOG("Initialization of DIF context failed\n"); 593192db8deSSlawomir Ptak return rc; 594192db8deSSlawomir Ptak } 595192db8deSSlawomir Ptak 596192db8deSSlawomir Ptak rc = spdk_dix_verify(iovs, iovcnt, &md_iov, num_blocks, &dif_ctx, &err_blk); 597192db8deSSlawomir Ptak if (rc != 0) { 598192db8deSSlawomir Ptak SPDK_ERRLOG("Reference tag check failed. type=%d, offset=%d" 599192db8deSSlawomir Ptak PRIu32 "\n", err_blk.err_type, err_blk.err_offset); 600192db8deSSlawomir Ptak } 601192db8deSSlawomir Ptak 602192db8deSSlawomir Ptak return rc; 603192db8deSSlawomir Ptak } 604192db8deSSlawomir Ptak 6056ba11b19SArtur Paszkiewicz void 6066ba11b19SArtur Paszkiewicz raid_bdev_io_complete(struct raid_bdev_io *raid_io, enum spdk_bdev_io_status status) 6076ba11b19SArtur Paszkiewicz { 6086ba11b19SArtur Paszkiewicz struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(raid_io); 609192db8deSSlawomir Ptak int rc; 6106ba11b19SArtur Paszkiewicz 6118d52c4c2Sxupeng-mingtu spdk_trace_record(TRACE_BDEV_RAID_IO_DONE, 0, 0, (uintptr_t)raid_io, (uintptr_t)bdev_io); 6128d52c4c2Sxupeng-mingtu 613aae5e04fSArtur Paszkiewicz if (raid_io->split.offset != RAID_OFFSET_BLOCKS_INVALID) { 614aae5e04fSArtur Paszkiewicz struct iovec *split_iov = raid_io->split.iov; 615aae5e04fSArtur Paszkiewicz const struct iovec *split_iov_orig = &raid_io->split.iov_copy; 616aae5e04fSArtur Paszkiewicz 617aae5e04fSArtur Paszkiewicz /* 618aae5e04fSArtur Paszkiewicz * Non-zero offset here means that this is the completion of the first part of the 619aae5e04fSArtur Paszkiewicz * split I/O (the higher LBAs). Then, we submit the second part and set offset to 0. 620aae5e04fSArtur Paszkiewicz */ 621aae5e04fSArtur Paszkiewicz if (raid_io->split.offset != 0) { 622aae5e04fSArtur Paszkiewicz raid_io->offset_blocks = bdev_io->u.bdev.offset_blocks; 623aae5e04fSArtur Paszkiewicz raid_io->md_buf = bdev_io->u.bdev.md_buf; 624aae5e04fSArtur Paszkiewicz 625aae5e04fSArtur Paszkiewicz if (status == SPDK_BDEV_IO_STATUS_SUCCESS) { 626aae5e04fSArtur Paszkiewicz raid_io->num_blocks = raid_io->split.offset; 627aae5e04fSArtur Paszkiewicz raid_io->iovcnt = raid_io->iovs - bdev_io->u.bdev.iovs; 628aae5e04fSArtur Paszkiewicz raid_io->iovs = bdev_io->u.bdev.iovs; 629aae5e04fSArtur Paszkiewicz if (split_iov != NULL) { 630aae5e04fSArtur Paszkiewicz raid_io->iovcnt++; 631aae5e04fSArtur Paszkiewicz split_iov->iov_len = split_iov->iov_base - split_iov_orig->iov_base; 632aae5e04fSArtur Paszkiewicz split_iov->iov_base = split_iov_orig->iov_base; 633aae5e04fSArtur Paszkiewicz } 634aae5e04fSArtur Paszkiewicz 635aae5e04fSArtur Paszkiewicz raid_io->split.offset = 0; 636aae5e04fSArtur Paszkiewicz raid_io->base_bdev_io_submitted = 0; 637aae5e04fSArtur Paszkiewicz raid_io->raid_ch = raid_io->raid_ch->process.ch_processed; 638aae5e04fSArtur Paszkiewicz 639aae5e04fSArtur Paszkiewicz raid_io->raid_bdev->module->submit_rw_request(raid_io); 640aae5e04fSArtur Paszkiewicz return; 641aae5e04fSArtur Paszkiewicz } 642aae5e04fSArtur Paszkiewicz } 643aae5e04fSArtur Paszkiewicz 644aae5e04fSArtur Paszkiewicz raid_io->num_blocks = bdev_io->u.bdev.num_blocks; 645aae5e04fSArtur Paszkiewicz raid_io->iovcnt = bdev_io->u.bdev.iovcnt; 646aae5e04fSArtur Paszkiewicz raid_io->iovs = bdev_io->u.bdev.iovs; 647aae5e04fSArtur Paszkiewicz if (split_iov != NULL) { 648aae5e04fSArtur Paszkiewicz *split_iov = *split_iov_orig; 649aae5e04fSArtur Paszkiewicz } 650aae5e04fSArtur Paszkiewicz } 651aae5e04fSArtur Paszkiewicz 6522b867a50SArtur Paszkiewicz if (spdk_unlikely(raid_io->completion_cb != NULL)) { 6532b867a50SArtur Paszkiewicz raid_io->completion_cb(raid_io, status); 6542b867a50SArtur Paszkiewicz } else { 655192db8deSSlawomir Ptak if (spdk_unlikely(bdev_io->type == SPDK_BDEV_IO_TYPE_READ && 656192db8deSSlawomir Ptak spdk_bdev_get_dif_type(bdev_io->bdev) != SPDK_DIF_DISABLE && 657192db8deSSlawomir Ptak bdev_io->bdev->dif_check_flags & SPDK_DIF_FLAGS_REFTAG_CHECK && 658192db8deSSlawomir Ptak status == SPDK_BDEV_IO_STATUS_SUCCESS)) { 659192db8deSSlawomir Ptak 660192db8deSSlawomir Ptak rc = raid_bdev_remap_dix_reftag(bdev_io->u.bdev.md_buf, 661192db8deSSlawomir Ptak bdev_io->u.bdev.num_blocks, bdev_io->bdev, 662192db8deSSlawomir Ptak bdev_io->u.bdev.offset_blocks); 663192db8deSSlawomir Ptak if (rc != 0) { 664192db8deSSlawomir Ptak status = SPDK_BDEV_IO_STATUS_FAILED; 665192db8deSSlawomir Ptak } 666192db8deSSlawomir Ptak } 6676ba11b19SArtur Paszkiewicz spdk_bdev_io_complete(bdev_io, status); 6686ba11b19SArtur Paszkiewicz } 6692b867a50SArtur Paszkiewicz } 6706ba11b19SArtur Paszkiewicz 67107fe6a43SSeth Howell /* 67207fe6a43SSeth Howell * brief: 6732efe6d92SArtur Paszkiewicz * raid_bdev_io_complete_part - signal the completion of a part of the expected 6742efe6d92SArtur Paszkiewicz * base bdev IOs and complete the raid_io if this is the final expected IO. 6752efe6d92SArtur Paszkiewicz * The caller should first set raid_io->base_bdev_io_remaining. This function 6762efe6d92SArtur Paszkiewicz * will decrement this counter by the value of the 'completed' parameter and 6772efe6d92SArtur Paszkiewicz * complete the raid_io if the counter reaches 0. The caller is free to 6782efe6d92SArtur Paszkiewicz * interpret the 'base_bdev_io_remaining' and 'completed' values as needed, 6792efe6d92SArtur Paszkiewicz * it can represent e.g. blocks or IOs. 680a5d9d778Spaul luse * params: 6812efe6d92SArtur Paszkiewicz * raid_io - pointer to raid_bdev_io 6822efe6d92SArtur Paszkiewicz * completed - the part of the raid_io that has been completed 6832efe6d92SArtur Paszkiewicz * status - status of the base IO 684a5d9d778Spaul luse * returns: 6852efe6d92SArtur Paszkiewicz * true - if the raid_io is completed 6862efe6d92SArtur Paszkiewicz * false - otherwise 687a5d9d778Spaul luse */ 6882efe6d92SArtur Paszkiewicz bool 6892efe6d92SArtur Paszkiewicz raid_bdev_io_complete_part(struct raid_bdev_io *raid_io, uint64_t completed, 6902efe6d92SArtur Paszkiewicz enum spdk_bdev_io_status status) 691a5d9d778Spaul luse { 6922efe6d92SArtur Paszkiewicz assert(raid_io->base_bdev_io_remaining >= completed); 6932efe6d92SArtur Paszkiewicz raid_io->base_bdev_io_remaining -= completed; 694a5d9d778Spaul luse 6959820a949SArtur Paszkiewicz if (status != raid_io->base_bdev_io_status_default) { 6962efe6d92SArtur Paszkiewicz raid_io->base_bdev_io_status = status; 697a5d9d778Spaul luse } 698a5d9d778Spaul luse 6992efe6d92SArtur Paszkiewicz if (raid_io->base_bdev_io_remaining == 0) { 7006ba11b19SArtur Paszkiewicz raid_bdev_io_complete(raid_io, raid_io->base_bdev_io_status); 7012efe6d92SArtur Paszkiewicz return true; 7022efe6d92SArtur Paszkiewicz } else { 7032efe6d92SArtur Paszkiewicz return false; 704a5d9d778Spaul luse } 705a5d9d778Spaul luse } 706a5d9d778Spaul luse 70707fe6a43SSeth Howell /* 70807fe6a43SSeth Howell * brief: 7091d246e97SArtur Paszkiewicz * raid_bdev_queue_io_wait function processes the IO which failed to submit. 7101d246e97SArtur Paszkiewicz * It will try to queue the IOs after storing the context to bdev wait queue logic. 71107fe6a43SSeth Howell * params: 712ae70d6a4SArtur Paszkiewicz * raid_io - pointer to raid_bdev_io 713ae70d6a4SArtur Paszkiewicz * bdev - the block device that the IO is submitted to 714ae70d6a4SArtur Paszkiewicz * ch - io channel 715ae70d6a4SArtur Paszkiewicz * cb_fn - callback when the spdk_bdev_io for bdev becomes available 71607fe6a43SSeth Howell * returns: 71707fe6a43SSeth Howell * none 71807fe6a43SSeth Howell */ 719fc9ca1d0SArtur Paszkiewicz void 720ae70d6a4SArtur Paszkiewicz raid_bdev_queue_io_wait(struct raid_bdev_io *raid_io, struct spdk_bdev *bdev, 721ae70d6a4SArtur Paszkiewicz struct spdk_io_channel *ch, spdk_bdev_io_wait_cb cb_fn) 72207fe6a43SSeth Howell { 723ae70d6a4SArtur Paszkiewicz raid_io->waitq_entry.bdev = bdev; 72407fe6a43SSeth Howell raid_io->waitq_entry.cb_fn = cb_fn; 725ae70d6a4SArtur Paszkiewicz raid_io->waitq_entry.cb_arg = raid_io; 726ae70d6a4SArtur Paszkiewicz spdk_bdev_queue_io_wait(bdev, ch, &raid_io->waitq_entry); 72707fe6a43SSeth Howell } 72807fe6a43SSeth Howell 7290ae5a89dSArtur Paszkiewicz static void 7302efe6d92SArtur Paszkiewicz raid_base_bdev_reset_complete(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg) 7312efe6d92SArtur Paszkiewicz { 7322efe6d92SArtur Paszkiewicz struct raid_bdev_io *raid_io = cb_arg; 7332efe6d92SArtur Paszkiewicz 7342efe6d92SArtur Paszkiewicz spdk_bdev_free_io(bdev_io); 7352efe6d92SArtur Paszkiewicz 7362efe6d92SArtur Paszkiewicz raid_bdev_io_complete_part(raid_io, 1, success ? 7372efe6d92SArtur Paszkiewicz SPDK_BDEV_IO_STATUS_SUCCESS : 7382efe6d92SArtur Paszkiewicz SPDK_BDEV_IO_STATUS_FAILED); 7392efe6d92SArtur Paszkiewicz } 7402efe6d92SArtur Paszkiewicz 7418dd1cd21SBen Walker static void raid_bdev_submit_reset_request(struct raid_bdev_io *raid_io); 7420ae5a89dSArtur Paszkiewicz 7430ae5a89dSArtur Paszkiewicz static void 744ae70d6a4SArtur Paszkiewicz _raid_bdev_submit_reset_request(void *_raid_io) 7450ae5a89dSArtur Paszkiewicz { 746ae70d6a4SArtur Paszkiewicz struct raid_bdev_io *raid_io = _raid_io; 7470ae5a89dSArtur Paszkiewicz 7480ae5a89dSArtur Paszkiewicz raid_bdev_submit_reset_request(raid_io); 7490ae5a89dSArtur Paszkiewicz } 7500ae5a89dSArtur Paszkiewicz 75107fe6a43SSeth Howell /* 75207fe6a43SSeth Howell * brief: 7530ae5a89dSArtur Paszkiewicz * raid_bdev_submit_reset_request function submits reset requests 75407fe6a43SSeth Howell * to member disks; it will submit as many as possible unless a reset fails with -ENOMEM, in 75507fe6a43SSeth Howell * which case it will queue it for later submission 75607fe6a43SSeth Howell * params: 7570ae5a89dSArtur Paszkiewicz * raid_io 75807fe6a43SSeth Howell * returns: 75907fe6a43SSeth Howell * none 76007fe6a43SSeth Howell */ 76107fe6a43SSeth Howell static void 7620ae5a89dSArtur Paszkiewicz raid_bdev_submit_reset_request(struct raid_bdev_io *raid_io) 76307fe6a43SSeth Howell { 76407fe6a43SSeth Howell struct raid_bdev *raid_bdev; 76507fe6a43SSeth Howell int ret; 76607fe6a43SSeth Howell uint8_t i; 767235cc2c9SArtur Paszkiewicz struct raid_base_bdev_info *base_info; 768235cc2c9SArtur Paszkiewicz struct spdk_io_channel *base_ch; 76907fe6a43SSeth Howell 770cb8dbf17SArtur Paszkiewicz raid_bdev = raid_io->raid_bdev; 77107fe6a43SSeth Howell 7722efe6d92SArtur Paszkiewicz if (raid_io->base_bdev_io_remaining == 0) { 7732efe6d92SArtur Paszkiewicz raid_io->base_bdev_io_remaining = raid_bdev->num_base_bdevs; 7742efe6d92SArtur Paszkiewicz } 77577b8618eSArtur Paszkiewicz 776fe7932a5SArtur Paszkiewicz for (i = raid_io->base_bdev_io_submitted; i < raid_bdev->num_base_bdevs; i++) { 777235cc2c9SArtur Paszkiewicz base_info = &raid_bdev->base_bdev_info[i]; 778235cc2c9SArtur Paszkiewicz base_ch = raid_io->raid_ch->base_channel[i]; 779b42cb0e5SArtur Paszkiewicz if (base_ch == NULL) { 780b42cb0e5SArtur Paszkiewicz raid_io->base_bdev_io_submitted++; 781b42cb0e5SArtur Paszkiewicz raid_bdev_io_complete_part(raid_io, 1, SPDK_BDEV_IO_STATUS_SUCCESS); 782b42cb0e5SArtur Paszkiewicz continue; 783b42cb0e5SArtur Paszkiewicz } 784235cc2c9SArtur Paszkiewicz ret = spdk_bdev_reset(base_info->desc, base_ch, 7852efe6d92SArtur Paszkiewicz raid_base_bdev_reset_complete, raid_io); 78607fe6a43SSeth Howell if (ret == 0) { 78707fe6a43SSeth Howell raid_io->base_bdev_io_submitted++; 788d3a04643SArtur Paszkiewicz } else if (ret == -ENOMEM) { 7898d1993a5SArtur Paszkiewicz raid_bdev_queue_io_wait(raid_io, spdk_bdev_desc_get_bdev(base_info->desc), 7908d1993a5SArtur Paszkiewicz base_ch, _raid_bdev_submit_reset_request); 791d3a04643SArtur Paszkiewicz return; 792d3a04643SArtur Paszkiewicz } else { 793d3a04643SArtur Paszkiewicz SPDK_ERRLOG("bdev io submit error not due to ENOMEM, it should not happen\n"); 794d3a04643SArtur Paszkiewicz assert(false); 7956ba11b19SArtur Paszkiewicz raid_bdev_io_complete(raid_io, SPDK_BDEV_IO_STATUS_FAILED); 79607fe6a43SSeth Howell return; 79707fe6a43SSeth Howell } 79807fe6a43SSeth Howell } 79907fe6a43SSeth Howell } 80007fe6a43SSeth Howell 801aae5e04fSArtur Paszkiewicz static void 802aae5e04fSArtur Paszkiewicz raid_bdev_io_split(struct raid_bdev_io *raid_io, uint64_t split_offset) 803aae5e04fSArtur Paszkiewicz { 804aae5e04fSArtur Paszkiewicz struct raid_bdev *raid_bdev = raid_io->raid_bdev; 805bb374988SArtur Paszkiewicz size_t iov_offset = split_offset * raid_bdev->bdev.blocklen; 806aae5e04fSArtur Paszkiewicz int i; 807aae5e04fSArtur Paszkiewicz 808aae5e04fSArtur Paszkiewicz assert(split_offset != 0); 809aae5e04fSArtur Paszkiewicz assert(raid_io->split.offset == RAID_OFFSET_BLOCKS_INVALID); 810aae5e04fSArtur Paszkiewicz raid_io->split.offset = split_offset; 811aae5e04fSArtur Paszkiewicz 812aae5e04fSArtur Paszkiewicz raid_io->offset_blocks += split_offset; 813aae5e04fSArtur Paszkiewicz raid_io->num_blocks -= split_offset; 814aae5e04fSArtur Paszkiewicz if (raid_io->md_buf != NULL) { 815aae5e04fSArtur Paszkiewicz raid_io->md_buf += (split_offset * raid_bdev->bdev.md_len); 816aae5e04fSArtur Paszkiewicz } 817aae5e04fSArtur Paszkiewicz 818aae5e04fSArtur Paszkiewicz for (i = 0; i < raid_io->iovcnt; i++) { 819aae5e04fSArtur Paszkiewicz struct iovec *iov = &raid_io->iovs[i]; 820aae5e04fSArtur Paszkiewicz 821aae5e04fSArtur Paszkiewicz if (iov_offset < iov->iov_len) { 822aae5e04fSArtur Paszkiewicz if (iov_offset == 0) { 823aae5e04fSArtur Paszkiewicz raid_io->split.iov = NULL; 824aae5e04fSArtur Paszkiewicz } else { 825aae5e04fSArtur Paszkiewicz raid_io->split.iov = iov; 826aae5e04fSArtur Paszkiewicz raid_io->split.iov_copy = *iov; 827aae5e04fSArtur Paszkiewicz iov->iov_base += iov_offset; 828aae5e04fSArtur Paszkiewicz iov->iov_len -= iov_offset; 829aae5e04fSArtur Paszkiewicz } 830aae5e04fSArtur Paszkiewicz raid_io->iovs += i; 831aae5e04fSArtur Paszkiewicz raid_io->iovcnt -= i; 832aae5e04fSArtur Paszkiewicz break; 833aae5e04fSArtur Paszkiewicz } 834aae5e04fSArtur Paszkiewicz 835aae5e04fSArtur Paszkiewicz iov_offset -= iov->iov_len; 836aae5e04fSArtur Paszkiewicz } 837aae5e04fSArtur Paszkiewicz } 838aae5e04fSArtur Paszkiewicz 839aae5e04fSArtur Paszkiewicz static void 840aae5e04fSArtur Paszkiewicz raid_bdev_submit_rw_request(struct raid_bdev_io *raid_io) 841aae5e04fSArtur Paszkiewicz { 842aae5e04fSArtur Paszkiewicz struct raid_bdev_io_channel *raid_ch = raid_io->raid_ch; 843aae5e04fSArtur Paszkiewicz 844aae5e04fSArtur Paszkiewicz if (raid_ch->process.offset != RAID_OFFSET_BLOCKS_INVALID) { 845aae5e04fSArtur Paszkiewicz uint64_t offset_begin = raid_io->offset_blocks; 846aae5e04fSArtur Paszkiewicz uint64_t offset_end = offset_begin + raid_io->num_blocks; 847aae5e04fSArtur Paszkiewicz 848aae5e04fSArtur Paszkiewicz if (offset_end > raid_ch->process.offset) { 849aae5e04fSArtur Paszkiewicz if (offset_begin < raid_ch->process.offset) { 850aae5e04fSArtur Paszkiewicz /* 851aae5e04fSArtur Paszkiewicz * If the I/O spans both the processed and unprocessed ranges, 852aae5e04fSArtur Paszkiewicz * split it and first handle the unprocessed part. After it 853aae5e04fSArtur Paszkiewicz * completes, the rest will be handled. 854aae5e04fSArtur Paszkiewicz * This situation occurs when the process thread is not active 855aae5e04fSArtur Paszkiewicz * or is waiting for the process window range to be locked 856aae5e04fSArtur Paszkiewicz * (quiesced). When a window is being processed, such I/Os will be 857aae5e04fSArtur Paszkiewicz * deferred by the bdev layer until the window is unlocked. 858aae5e04fSArtur Paszkiewicz */ 859aae5e04fSArtur Paszkiewicz SPDK_DEBUGLOG(bdev_raid, "split: process_offset: %lu offset_begin: %lu offset_end: %lu\n", 860aae5e04fSArtur Paszkiewicz raid_ch->process.offset, offset_begin, offset_end); 861aae5e04fSArtur Paszkiewicz raid_bdev_io_split(raid_io, raid_ch->process.offset - offset_begin); 862aae5e04fSArtur Paszkiewicz } 863aae5e04fSArtur Paszkiewicz } else { 864aae5e04fSArtur Paszkiewicz /* Use the child channel, which corresponds to the already processed range */ 865aae5e04fSArtur Paszkiewicz raid_io->raid_ch = raid_ch->process.ch_processed; 866aae5e04fSArtur Paszkiewicz } 867aae5e04fSArtur Paszkiewicz } 868aae5e04fSArtur Paszkiewicz 869aae5e04fSArtur Paszkiewicz raid_io->raid_bdev->module->submit_rw_request(raid_io); 870aae5e04fSArtur Paszkiewicz } 871aae5e04fSArtur Paszkiewicz 87207fe6a43SSeth Howell /* 87307fe6a43SSeth Howell * brief: 87407fe6a43SSeth Howell * Callback function to spdk_bdev_io_get_buf. 87507fe6a43SSeth Howell * params: 87607fe6a43SSeth Howell * ch - pointer to raid bdev io channel 87707fe6a43SSeth Howell * bdev_io - pointer to parent bdev_io on raid bdev device 87807fe6a43SSeth Howell * success - True if buffer is allocated or false otherwise. 87907fe6a43SSeth Howell * returns: 88007fe6a43SSeth Howell * none 88107fe6a43SSeth Howell */ 88207fe6a43SSeth Howell static void 88307fe6a43SSeth Howell raid_bdev_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io, 88407fe6a43SSeth Howell bool success) 88507fe6a43SSeth Howell { 8860ae5a89dSArtur Paszkiewicz struct raid_bdev_io *raid_io = (struct raid_bdev_io *)bdev_io->driver_ctx; 8870ae5a89dSArtur Paszkiewicz 88807fe6a43SSeth Howell if (!success) { 8896ba11b19SArtur Paszkiewicz raid_bdev_io_complete(raid_io, SPDK_BDEV_IO_STATUS_FAILED); 89007fe6a43SSeth Howell return; 89107fe6a43SSeth Howell } 89207fe6a43SSeth Howell 8935031f0f3SSlawomir Ptak raid_io->iovs = bdev_io->u.bdev.iovs; 8945031f0f3SSlawomir Ptak raid_io->iovcnt = bdev_io->u.bdev.iovcnt; 8955031f0f3SSlawomir Ptak raid_io->md_buf = bdev_io->u.bdev.md_buf; 8965031f0f3SSlawomir Ptak 897aae5e04fSArtur Paszkiewicz raid_bdev_submit_rw_request(raid_io); 89807fe6a43SSeth Howell } 89907fe6a43SSeth Howell 900a4e1703eSArtur Paszkiewicz void 901a4e1703eSArtur Paszkiewicz raid_bdev_io_init(struct raid_bdev_io *raid_io, struct raid_bdev_io_channel *raid_ch, 902a4e1703eSArtur Paszkiewicz enum spdk_bdev_io_type type, uint64_t offset_blocks, 903a4e1703eSArtur Paszkiewicz uint64_t num_blocks, struct iovec *iovs, int iovcnt, void *md_buf, 904a4e1703eSArtur Paszkiewicz struct spdk_memory_domain *memory_domain, void *memory_domain_ctx) 905a4e1703eSArtur Paszkiewicz { 906a4e1703eSArtur Paszkiewicz struct spdk_io_channel *ch = spdk_io_channel_from_ctx(raid_ch); 907a4e1703eSArtur Paszkiewicz struct raid_bdev *raid_bdev = spdk_io_channel_get_io_device(ch); 908a4e1703eSArtur Paszkiewicz 909a4e1703eSArtur Paszkiewicz raid_io->type = type; 910a4e1703eSArtur Paszkiewicz raid_io->offset_blocks = offset_blocks; 911a4e1703eSArtur Paszkiewicz raid_io->num_blocks = num_blocks; 912a4e1703eSArtur Paszkiewicz raid_io->iovs = iovs; 913a4e1703eSArtur Paszkiewicz raid_io->iovcnt = iovcnt; 914a4e1703eSArtur Paszkiewicz raid_io->memory_domain = memory_domain; 915a4e1703eSArtur Paszkiewicz raid_io->memory_domain_ctx = memory_domain_ctx; 916a4e1703eSArtur Paszkiewicz raid_io->md_buf = md_buf; 917a4e1703eSArtur Paszkiewicz 918a4e1703eSArtur Paszkiewicz raid_io->raid_bdev = raid_bdev; 919a4e1703eSArtur Paszkiewicz raid_io->raid_ch = raid_ch; 920a4e1703eSArtur Paszkiewicz raid_io->base_bdev_io_remaining = 0; 921a4e1703eSArtur Paszkiewicz raid_io->base_bdev_io_submitted = 0; 9222b867a50SArtur Paszkiewicz raid_io->completion_cb = NULL; 923aae5e04fSArtur Paszkiewicz raid_io->split.offset = RAID_OFFSET_BLOCKS_INVALID; 9249820a949SArtur Paszkiewicz 9259820a949SArtur Paszkiewicz raid_bdev_io_set_default_status(raid_io, SPDK_BDEV_IO_STATUS_SUCCESS); 926a4e1703eSArtur Paszkiewicz } 927a4e1703eSArtur Paszkiewicz 92807fe6a43SSeth Howell /* 92907fe6a43SSeth Howell * brief: 93007fe6a43SSeth Howell * raid_bdev_submit_request function is the submit_request function pointer of 93107fe6a43SSeth Howell * raid bdev function table. This is used to submit the io on raid_bdev to below 93207fe6a43SSeth Howell * layers. 93307fe6a43SSeth Howell * params: 93407fe6a43SSeth Howell * ch - pointer to raid bdev io channel 93507fe6a43SSeth Howell * bdev_io - pointer to parent bdev_io on raid bdev device 93607fe6a43SSeth Howell * returns: 93707fe6a43SSeth Howell * none 93807fe6a43SSeth Howell */ 93907fe6a43SSeth Howell static void 94007fe6a43SSeth Howell raid_bdev_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io) 94107fe6a43SSeth Howell { 942485c7912SArtur Paszkiewicz struct raid_bdev_io *raid_io = (struct raid_bdev_io *)bdev_io->driver_ctx; 943485c7912SArtur Paszkiewicz 944a4e1703eSArtur Paszkiewicz raid_bdev_io_init(raid_io, spdk_io_channel_get_ctx(ch), bdev_io->type, 945a4e1703eSArtur Paszkiewicz bdev_io->u.bdev.offset_blocks, bdev_io->u.bdev.num_blocks, 946a4e1703eSArtur Paszkiewicz bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt, bdev_io->u.bdev.md_buf, 947a4e1703eSArtur Paszkiewicz bdev_io->u.bdev.memory_domain, bdev_io->u.bdev.memory_domain_ctx); 948485c7912SArtur Paszkiewicz 9498d52c4c2Sxupeng-mingtu spdk_trace_record(TRACE_BDEV_RAID_IO_START, 0, 0, (uintptr_t)raid_io, (uintptr_t)bdev_io); 9508d52c4c2Sxupeng-mingtu 95107fe6a43SSeth Howell switch (bdev_io->type) { 95207fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_READ: 95307fe6a43SSeth Howell spdk_bdev_io_get_buf(bdev_io, raid_bdev_get_buf_cb, 95407fe6a43SSeth Howell bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen); 95507fe6a43SSeth Howell break; 95607fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_WRITE: 957aae5e04fSArtur Paszkiewicz raid_bdev_submit_rw_request(raid_io); 95807fe6a43SSeth Howell break; 95907fe6a43SSeth Howell 96007fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_RESET: 9610ae5a89dSArtur Paszkiewicz raid_bdev_submit_reset_request(raid_io); 96207fe6a43SSeth Howell break; 96307fe6a43SSeth Howell 96407fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_FLUSH: 96507fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_UNMAP: 966aae5e04fSArtur Paszkiewicz if (raid_io->raid_bdev->process != NULL) { 967aae5e04fSArtur Paszkiewicz /* TODO: rebuild support */ 968aae5e04fSArtur Paszkiewicz raid_bdev_io_complete(raid_io, SPDK_BDEV_IO_STATUS_FAILED); 969aae5e04fSArtur Paszkiewicz return; 970aae5e04fSArtur Paszkiewicz } 971182278c0SArtur Paszkiewicz raid_io->raid_bdev->module->submit_null_payload_request(raid_io); 97207fe6a43SSeth Howell break; 97307fe6a43SSeth Howell 97407fe6a43SSeth Howell default: 97507fe6a43SSeth Howell SPDK_ERRLOG("submit request, invalid io type %u\n", bdev_io->type); 9766ba11b19SArtur Paszkiewicz raid_bdev_io_complete(raid_io, SPDK_BDEV_IO_STATUS_FAILED); 97707fe6a43SSeth Howell break; 97807fe6a43SSeth Howell } 97907fe6a43SSeth Howell } 98007fe6a43SSeth Howell 98107fe6a43SSeth Howell /* 98207fe6a43SSeth Howell * brief: 98307fe6a43SSeth Howell * _raid_bdev_io_type_supported checks whether io_type is supported in 98407fe6a43SSeth Howell * all base bdev modules of raid bdev module. If anyone among the base_bdevs 98507fe6a43SSeth Howell * doesn't support, the raid device doesn't supports. 98607fe6a43SSeth Howell * 98707fe6a43SSeth Howell * params: 98807fe6a43SSeth Howell * raid_bdev - pointer to raid bdev context 98907fe6a43SSeth Howell * io_type - io type 99007fe6a43SSeth Howell * returns: 99107fe6a43SSeth Howell * true - io_type is supported 99207fe6a43SSeth Howell * false - io_type is not supported 99307fe6a43SSeth Howell */ 99407fe6a43SSeth Howell inline static bool 99507fe6a43SSeth Howell _raid_bdev_io_type_supported(struct raid_bdev *raid_bdev, enum spdk_bdev_io_type io_type) 99607fe6a43SSeth Howell { 997a193dcb8SArtur Paszkiewicz struct raid_base_bdev_info *base_info; 99807fe6a43SSeth Howell 9991d3ca5c4SArtur Paszkiewicz if (io_type == SPDK_BDEV_IO_TYPE_FLUSH || 10001d3ca5c4SArtur Paszkiewicz io_type == SPDK_BDEV_IO_TYPE_UNMAP) { 10011d3ca5c4SArtur Paszkiewicz if (raid_bdev->module->submit_null_payload_request == NULL) { 10021d3ca5c4SArtur Paszkiewicz return false; 10031d3ca5c4SArtur Paszkiewicz } 10041d3ca5c4SArtur Paszkiewicz } 10051d3ca5c4SArtur Paszkiewicz 1006a193dcb8SArtur Paszkiewicz RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) { 10078d1993a5SArtur Paszkiewicz if (base_info->desc == NULL) { 100807fe6a43SSeth Howell continue; 100907fe6a43SSeth Howell } 101007fe6a43SSeth Howell 10118d1993a5SArtur Paszkiewicz if (spdk_bdev_io_type_supported(spdk_bdev_desc_get_bdev(base_info->desc), io_type) == false) { 101207fe6a43SSeth Howell return false; 101307fe6a43SSeth Howell } 101407fe6a43SSeth Howell } 101507fe6a43SSeth Howell 101607fe6a43SSeth Howell return true; 101707fe6a43SSeth Howell } 101807fe6a43SSeth Howell 101907fe6a43SSeth Howell /* 102007fe6a43SSeth Howell * brief: 102107fe6a43SSeth Howell * raid_bdev_io_type_supported is the io_supported function for bdev function 102207fe6a43SSeth Howell * table which returns whether the particular io type is supported or not by 102307fe6a43SSeth Howell * raid bdev module 102407fe6a43SSeth Howell * params: 102507fe6a43SSeth Howell * ctx - pointer to raid bdev context 102607fe6a43SSeth Howell * type - io type 102707fe6a43SSeth Howell * returns: 102807fe6a43SSeth Howell * true - io_type is supported 102907fe6a43SSeth Howell * false - io_type is not supported 103007fe6a43SSeth Howell */ 103107fe6a43SSeth Howell static bool 103207fe6a43SSeth Howell raid_bdev_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type) 103307fe6a43SSeth Howell { 103407fe6a43SSeth Howell switch (io_type) { 103507fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_READ: 103607fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_WRITE: 103707fe6a43SSeth Howell return true; 103807fe6a43SSeth Howell 103907fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_FLUSH: 104007fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_RESET: 104107fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_UNMAP: 104207fe6a43SSeth Howell return _raid_bdev_io_type_supported(ctx, io_type); 104307fe6a43SSeth Howell 104407fe6a43SSeth Howell default: 104507fe6a43SSeth Howell return false; 104607fe6a43SSeth Howell } 104707fe6a43SSeth Howell 104807fe6a43SSeth Howell return false; 104907fe6a43SSeth Howell } 105007fe6a43SSeth Howell 105107fe6a43SSeth Howell /* 105207fe6a43SSeth Howell * brief: 105307fe6a43SSeth Howell * raid_bdev_get_io_channel is the get_io_channel function table pointer for 105407fe6a43SSeth Howell * raid bdev. This is used to return the io channel for this raid bdev 105507fe6a43SSeth Howell * params: 105607fe6a43SSeth Howell * ctxt - pointer to raid_bdev 105707fe6a43SSeth Howell * returns: 105807fe6a43SSeth Howell * pointer to io channel for raid bdev 105907fe6a43SSeth Howell */ 106007fe6a43SSeth Howell static struct spdk_io_channel * 106107fe6a43SSeth Howell raid_bdev_get_io_channel(void *ctxt) 106207fe6a43SSeth Howell { 106307fe6a43SSeth Howell struct raid_bdev *raid_bdev = ctxt; 106407fe6a43SSeth Howell 106507fe6a43SSeth Howell return spdk_get_io_channel(raid_bdev); 106607fe6a43SSeth Howell } 106707fe6a43SSeth Howell 1068ec6d94b6SArtur Paszkiewicz void 1069ec6d94b6SArtur Paszkiewicz raid_bdev_write_info_json(struct raid_bdev *raid_bdev, struct spdk_json_write_ctx *w) 107007fe6a43SSeth Howell { 1071a193dcb8SArtur Paszkiewicz struct raid_base_bdev_info *base_info; 107207fe6a43SSeth Howell 107307fe6a43SSeth Howell assert(raid_bdev != NULL); 10744dd2a0d3SArtur Paszkiewicz assert(spdk_get_thread() == spdk_thread_get_app_thread()); 107507fe6a43SSeth Howell 107656317f62SEugene Kobyak spdk_json_write_named_uuid(w, "uuid", &raid_bdev->bdev.uuid); 107707fe6a43SSeth Howell spdk_json_write_named_uint32(w, "strip_size_kb", raid_bdev->strip_size_kb); 107846ff15a6SArtur Paszkiewicz spdk_json_write_named_string(w, "state", raid_bdev_state_to_str(raid_bdev->state)); 1079445e667fSArtur Paszkiewicz spdk_json_write_named_string(w, "raid_level", raid_bdev_level_to_str(raid_bdev->level)); 10803bb8256aSArtur Paszkiewicz spdk_json_write_named_bool(w, "superblock", raid_bdev->superblock_enabled); 108107fe6a43SSeth Howell spdk_json_write_named_uint32(w, "num_base_bdevs", raid_bdev->num_base_bdevs); 108207fe6a43SSeth Howell spdk_json_write_named_uint32(w, "num_base_bdevs_discovered", raid_bdev->num_base_bdevs_discovered); 1083255d0786SArtur Paszkiewicz spdk_json_write_named_uint32(w, "num_base_bdevs_operational", 1084255d0786SArtur Paszkiewicz raid_bdev->num_base_bdevs_operational); 108550d58ff3SArtur Paszkiewicz if (raid_bdev->process) { 108650d58ff3SArtur Paszkiewicz struct raid_bdev_process *process = raid_bdev->process; 108750d58ff3SArtur Paszkiewicz uint64_t offset = process->window_offset; 108850d58ff3SArtur Paszkiewicz 108950d58ff3SArtur Paszkiewicz spdk_json_write_named_object_begin(w, "process"); 109050d58ff3SArtur Paszkiewicz spdk_json_write_name(w, "type"); 109150d58ff3SArtur Paszkiewicz spdk_json_write_string(w, raid_bdev_process_to_str(process->type)); 109250d58ff3SArtur Paszkiewicz spdk_json_write_named_string(w, "target", process->target->name); 109350d58ff3SArtur Paszkiewicz spdk_json_write_named_object_begin(w, "progress"); 109450d58ff3SArtur Paszkiewicz spdk_json_write_named_uint64(w, "blocks", offset); 109550d58ff3SArtur Paszkiewicz spdk_json_write_named_uint32(w, "percent", offset * 100.0 / raid_bdev->bdev.blockcnt); 109650d58ff3SArtur Paszkiewicz spdk_json_write_object_end(w); 109750d58ff3SArtur Paszkiewicz spdk_json_write_object_end(w); 109850d58ff3SArtur Paszkiewicz } 109907fe6a43SSeth Howell spdk_json_write_name(w, "base_bdevs_list"); 110007fe6a43SSeth Howell spdk_json_write_array_begin(w); 1101a193dcb8SArtur Paszkiewicz RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) { 1102c51db566SArtur Paszkiewicz spdk_json_write_object_begin(w); 1103c51db566SArtur Paszkiewicz spdk_json_write_name(w, "name"); 1104c51db566SArtur Paszkiewicz if (base_info->name) { 1105c51db566SArtur Paszkiewicz spdk_json_write_string(w, base_info->name); 110607fe6a43SSeth Howell } else { 110707fe6a43SSeth Howell spdk_json_write_null(w); 110807fe6a43SSeth Howell } 110956317f62SEugene Kobyak spdk_json_write_named_uuid(w, "uuid", &base_info->uuid); 1110c51db566SArtur Paszkiewicz spdk_json_write_named_bool(w, "is_configured", base_info->is_configured); 1111c51db566SArtur Paszkiewicz spdk_json_write_named_uint64(w, "data_offset", base_info->data_offset); 1112c51db566SArtur Paszkiewicz spdk_json_write_named_uint64(w, "data_size", base_info->data_size); 1113c51db566SArtur Paszkiewicz spdk_json_write_object_end(w); 111407fe6a43SSeth Howell } 111507fe6a43SSeth Howell spdk_json_write_array_end(w); 1116ec6d94b6SArtur Paszkiewicz } 1117ec6d94b6SArtur Paszkiewicz 1118ec6d94b6SArtur Paszkiewicz /* 1119ec6d94b6SArtur Paszkiewicz * brief: 1120ec6d94b6SArtur Paszkiewicz * raid_bdev_dump_info_json is the function table pointer for raid bdev 1121ec6d94b6SArtur Paszkiewicz * params: 1122ec6d94b6SArtur Paszkiewicz * ctx - pointer to raid_bdev 1123ec6d94b6SArtur Paszkiewicz * w - pointer to json context 1124ec6d94b6SArtur Paszkiewicz * returns: 1125ec6d94b6SArtur Paszkiewicz * 0 - success 1126ec6d94b6SArtur Paszkiewicz * non zero - failure 1127ec6d94b6SArtur Paszkiewicz */ 1128ec6d94b6SArtur Paszkiewicz static int 1129ec6d94b6SArtur Paszkiewicz raid_bdev_dump_info_json(void *ctx, struct spdk_json_write_ctx *w) 1130ec6d94b6SArtur Paszkiewicz { 1131ec6d94b6SArtur Paszkiewicz struct raid_bdev *raid_bdev = ctx; 1132ec6d94b6SArtur Paszkiewicz 1133ec6d94b6SArtur Paszkiewicz SPDK_DEBUGLOG(bdev_raid, "raid_bdev_dump_config_json\n"); 1134ec6d94b6SArtur Paszkiewicz 1135ec6d94b6SArtur Paszkiewicz /* Dump the raid bdev configuration related information */ 1136ec6d94b6SArtur Paszkiewicz spdk_json_write_named_object_begin(w, "raid"); 1137ec6d94b6SArtur Paszkiewicz raid_bdev_write_info_json(raid_bdev, w); 113807fe6a43SSeth Howell spdk_json_write_object_end(w); 113907fe6a43SSeth Howell 114007fe6a43SSeth Howell return 0; 114107fe6a43SSeth Howell } 114207fe6a43SSeth Howell 114307fe6a43SSeth Howell /* 114407fe6a43SSeth Howell * brief: 114507fe6a43SSeth Howell * raid_bdev_write_config_json is the function table pointer for raid bdev 114607fe6a43SSeth Howell * params: 114707fe6a43SSeth Howell * bdev - pointer to spdk_bdev 114807fe6a43SSeth Howell * w - pointer to json context 114907fe6a43SSeth Howell * returns: 115007fe6a43SSeth Howell * none 115107fe6a43SSeth Howell */ 115207fe6a43SSeth Howell static void 115307fe6a43SSeth Howell raid_bdev_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w) 115407fe6a43SSeth Howell { 115507fe6a43SSeth Howell struct raid_bdev *raid_bdev = bdev->ctxt; 1156a193dcb8SArtur Paszkiewicz struct raid_base_bdev_info *base_info; 115707fe6a43SSeth Howell 11584dd2a0d3SArtur Paszkiewicz assert(spdk_get_thread() == spdk_thread_get_app_thread()); 11594dd2a0d3SArtur Paszkiewicz 11603bb8256aSArtur Paszkiewicz if (raid_bdev->superblock_enabled) { 1161deed7d2fSArtur Paszkiewicz /* raid bdev configuration is stored in the superblock */ 1162deed7d2fSArtur Paszkiewicz return; 1163deed7d2fSArtur Paszkiewicz } 1164deed7d2fSArtur Paszkiewicz 116507fe6a43SSeth Howell spdk_json_write_object_begin(w); 116607fe6a43SSeth Howell 1167f0731534SMaciej Wawryk spdk_json_write_named_string(w, "method", "bdev_raid_create"); 116807fe6a43SSeth Howell 116907fe6a43SSeth Howell spdk_json_write_named_object_begin(w, "params"); 117007fe6a43SSeth Howell spdk_json_write_named_string(w, "name", bdev->name); 117156317f62SEugene Kobyak spdk_json_write_named_uuid(w, "uuid", &raid_bdev->bdev.uuid); 117296aff3c9SArtur Paszkiewicz if (raid_bdev->strip_size_kb != 0) { 1173af4fa148SWANGHAILIANG spdk_json_write_named_uint32(w, "strip_size_kb", raid_bdev->strip_size_kb); 117496aff3c9SArtur Paszkiewicz } 1175445e667fSArtur Paszkiewicz spdk_json_write_named_string(w, "raid_level", raid_bdev_level_to_str(raid_bdev->level)); 117607fe6a43SSeth Howell 117707fe6a43SSeth Howell spdk_json_write_named_array_begin(w, "base_bdevs"); 1178a193dcb8SArtur Paszkiewicz RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) { 117996aff3c9SArtur Paszkiewicz if (base_info->name) { 118096aff3c9SArtur Paszkiewicz spdk_json_write_string(w, base_info->name); 118196aff3c9SArtur Paszkiewicz } else { 118296aff3c9SArtur Paszkiewicz char str[32]; 118396aff3c9SArtur Paszkiewicz 118496aff3c9SArtur Paszkiewicz snprintf(str, sizeof(str), "removed_base_bdev_%u", raid_bdev_base_bdev_slot(base_info)); 118596aff3c9SArtur Paszkiewicz spdk_json_write_string(w, str); 118607fe6a43SSeth Howell } 118707fe6a43SSeth Howell } 118807fe6a43SSeth Howell spdk_json_write_array_end(w); 118907fe6a43SSeth Howell spdk_json_write_object_end(w); 119007fe6a43SSeth Howell 119107fe6a43SSeth Howell spdk_json_write_object_end(w); 119207fe6a43SSeth Howell } 119307fe6a43SSeth Howell 1194be440c01SAlexey Marchuk static int 1195be440c01SAlexey Marchuk raid_bdev_get_memory_domains(void *ctx, struct spdk_memory_domain **domains, int array_size) 1196be440c01SAlexey Marchuk { 1197be440c01SAlexey Marchuk struct raid_bdev *raid_bdev = ctx; 1198973b0d62SArtur Paszkiewicz struct raid_base_bdev_info *base_info; 1199b42cb0e5SArtur Paszkiewicz int domains_count = 0, rc = 0; 1200be440c01SAlexey Marchuk 120172672d49SArtur Paszkiewicz if (raid_bdev->module->memory_domains_supported == false) { 120272672d49SArtur Paszkiewicz return 0; 120372672d49SArtur Paszkiewicz } 120472672d49SArtur Paszkiewicz 1205be440c01SAlexey Marchuk /* First loop to get the number of memory domains */ 1206973b0d62SArtur Paszkiewicz RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) { 12076518a98dSArtur Paszkiewicz if (base_info->is_configured == false) { 1208b42cb0e5SArtur Paszkiewicz continue; 1209b42cb0e5SArtur Paszkiewicz } 12108d1993a5SArtur Paszkiewicz rc = spdk_bdev_get_memory_domains(spdk_bdev_desc_get_bdev(base_info->desc), NULL, 0); 1211be440c01SAlexey Marchuk if (rc < 0) { 12126518a98dSArtur Paszkiewicz return rc; 1213be440c01SAlexey Marchuk } 1214be440c01SAlexey Marchuk domains_count += rc; 1215be440c01SAlexey Marchuk } 1216be440c01SAlexey Marchuk 1217be440c01SAlexey Marchuk if (!domains || array_size < domains_count) { 12186518a98dSArtur Paszkiewicz return domains_count; 1219be440c01SAlexey Marchuk } 1220be440c01SAlexey Marchuk 1221973b0d62SArtur Paszkiewicz RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) { 12226518a98dSArtur Paszkiewicz if (base_info->is_configured == false) { 1223b42cb0e5SArtur Paszkiewicz continue; 1224b42cb0e5SArtur Paszkiewicz } 12258d1993a5SArtur Paszkiewicz rc = spdk_bdev_get_memory_domains(spdk_bdev_desc_get_bdev(base_info->desc), domains, array_size); 1226be440c01SAlexey Marchuk if (rc < 0) { 12276518a98dSArtur Paszkiewicz return rc; 1228be440c01SAlexey Marchuk } 1229be440c01SAlexey Marchuk domains += rc; 1230be440c01SAlexey Marchuk array_size -= rc; 1231be440c01SAlexey Marchuk } 1232be440c01SAlexey Marchuk 1233be440c01SAlexey Marchuk return domains_count; 1234be440c01SAlexey Marchuk } 1235be440c01SAlexey Marchuk 123607fe6a43SSeth Howell /* g_raid_bdev_fn_table is the function table for raid bdev */ 123707fe6a43SSeth Howell static const struct spdk_bdev_fn_table g_raid_bdev_fn_table = { 123807fe6a43SSeth Howell .destruct = raid_bdev_destruct, 123907fe6a43SSeth Howell .submit_request = raid_bdev_submit_request, 124007fe6a43SSeth Howell .io_type_supported = raid_bdev_io_type_supported, 124107fe6a43SSeth Howell .get_io_channel = raid_bdev_get_io_channel, 124207fe6a43SSeth Howell .dump_info_json = raid_bdev_dump_info_json, 124307fe6a43SSeth Howell .write_config_json = raid_bdev_write_config_json, 1244be440c01SAlexey Marchuk .get_memory_domains = raid_bdev_get_memory_domains, 124507fe6a43SSeth Howell }; 124607fe6a43SSeth Howell 1247dccdd1e5SArtur Paszkiewicz struct raid_bdev * 1248dccdd1e5SArtur Paszkiewicz raid_bdev_find_by_name(const char *name) 124907fe6a43SSeth Howell { 1250dccdd1e5SArtur Paszkiewicz struct raid_bdev *raid_bdev; 125107fe6a43SSeth Howell 1252dccdd1e5SArtur Paszkiewicz TAILQ_FOREACH(raid_bdev, &g_raid_bdev_list, global_link) { 1253dccdd1e5SArtur Paszkiewicz if (strcmp(raid_bdev->bdev.name, name) == 0) { 1254dccdd1e5SArtur Paszkiewicz return raid_bdev; 125507fe6a43SSeth Howell } 125607fe6a43SSeth Howell } 125707fe6a43SSeth Howell 1258dccdd1e5SArtur Paszkiewicz return NULL; 125907fe6a43SSeth Howell } 1260445e667fSArtur Paszkiewicz 1261688de1b9SArtur Paszkiewicz static struct raid_bdev * 1262688de1b9SArtur Paszkiewicz raid_bdev_find_by_uuid(const struct spdk_uuid *uuid) 1263688de1b9SArtur Paszkiewicz { 1264688de1b9SArtur Paszkiewicz struct raid_bdev *raid_bdev; 1265688de1b9SArtur Paszkiewicz 1266688de1b9SArtur Paszkiewicz TAILQ_FOREACH(raid_bdev, &g_raid_bdev_list, global_link) { 1267688de1b9SArtur Paszkiewicz if (spdk_uuid_compare(&raid_bdev->bdev.uuid, uuid) == 0) { 1268688de1b9SArtur Paszkiewicz return raid_bdev; 1269688de1b9SArtur Paszkiewicz } 1270688de1b9SArtur Paszkiewicz } 1271688de1b9SArtur Paszkiewicz 1272688de1b9SArtur Paszkiewicz return NULL; 1273688de1b9SArtur Paszkiewicz } 1274688de1b9SArtur Paszkiewicz 1275445e667fSArtur Paszkiewicz static struct { 1276445e667fSArtur Paszkiewicz const char *name; 1277445e667fSArtur Paszkiewicz enum raid_level value; 1278445e667fSArtur Paszkiewicz } g_raid_level_names[] = { 1279445e667fSArtur Paszkiewicz { "raid0", RAID0 }, 1280445e667fSArtur Paszkiewicz { "0", RAID0 }, 1281208f21cdSKrzysztof Smolinski { "raid1", RAID1 }, 1282208f21cdSKrzysztof Smolinski { "1", RAID1 }, 128383a4b155SArtur Paszkiewicz { "raid5f", RAID5F }, 128483a4b155SArtur Paszkiewicz { "5f", RAID5F }, 128564eebbd1Syupeng { "concat", CONCAT }, 1286445e667fSArtur Paszkiewicz { } 1287445e667fSArtur Paszkiewicz }; 1288445e667fSArtur Paszkiewicz 12890ea6e36aSArtur Paszkiewicz const char *g_raid_state_names[] = { 12900ea6e36aSArtur Paszkiewicz [RAID_BDEV_STATE_ONLINE] = "online", 12910ea6e36aSArtur Paszkiewicz [RAID_BDEV_STATE_CONFIGURING] = "configuring", 12920ea6e36aSArtur Paszkiewicz [RAID_BDEV_STATE_OFFLINE] = "offline", 12930ea6e36aSArtur Paszkiewicz [RAID_BDEV_STATE_MAX] = NULL 129446ff15a6SArtur Paszkiewicz }; 129546ff15a6SArtur Paszkiewicz 129650d58ff3SArtur Paszkiewicz static const char *g_raid_process_type_names[] = { 129750d58ff3SArtur Paszkiewicz [RAID_PROCESS_NONE] = "none", 129850d58ff3SArtur Paszkiewicz [RAID_PROCESS_REBUILD] = "rebuild", 129950d58ff3SArtur Paszkiewicz [RAID_PROCESS_MAX] = NULL 130050d58ff3SArtur Paszkiewicz }; 130150d58ff3SArtur Paszkiewicz 13028dd1cd21SBen Walker /* We have to use the typedef in the function declaration to appease astyle. */ 13038dd1cd21SBen Walker typedef enum raid_level raid_level_t; 130446ff15a6SArtur Paszkiewicz typedef enum raid_bdev_state raid_bdev_state_t; 13058dd1cd21SBen Walker 13068dd1cd21SBen Walker raid_level_t 130746ff15a6SArtur Paszkiewicz raid_bdev_str_to_level(const char *str) 1308445e667fSArtur Paszkiewicz { 1309445e667fSArtur Paszkiewicz unsigned int i; 1310445e667fSArtur Paszkiewicz 1311a2606d4bSMaciej Szwed assert(str != NULL); 1312a2606d4bSMaciej Szwed 1313445e667fSArtur Paszkiewicz for (i = 0; g_raid_level_names[i].name != NULL; i++) { 1314445e667fSArtur Paszkiewicz if (strcasecmp(g_raid_level_names[i].name, str) == 0) { 1315445e667fSArtur Paszkiewicz return g_raid_level_names[i].value; 1316445e667fSArtur Paszkiewicz } 1317445e667fSArtur Paszkiewicz } 1318445e667fSArtur Paszkiewicz 1319445e667fSArtur Paszkiewicz return INVALID_RAID_LEVEL; 1320445e667fSArtur Paszkiewicz } 1321445e667fSArtur Paszkiewicz 1322445e667fSArtur Paszkiewicz const char * 1323445e667fSArtur Paszkiewicz raid_bdev_level_to_str(enum raid_level level) 1324445e667fSArtur Paszkiewicz { 1325445e667fSArtur Paszkiewicz unsigned int i; 1326445e667fSArtur Paszkiewicz 1327445e667fSArtur Paszkiewicz for (i = 0; g_raid_level_names[i].name != NULL; i++) { 1328445e667fSArtur Paszkiewicz if (g_raid_level_names[i].value == level) { 1329445e667fSArtur Paszkiewicz return g_raid_level_names[i].name; 1330445e667fSArtur Paszkiewicz } 1331445e667fSArtur Paszkiewicz } 1332445e667fSArtur Paszkiewicz 1333445e667fSArtur Paszkiewicz return ""; 1334445e667fSArtur Paszkiewicz } 1335445e667fSArtur Paszkiewicz 133646ff15a6SArtur Paszkiewicz raid_bdev_state_t 133746ff15a6SArtur Paszkiewicz raid_bdev_str_to_state(const char *str) 133846ff15a6SArtur Paszkiewicz { 133946ff15a6SArtur Paszkiewicz unsigned int i; 134046ff15a6SArtur Paszkiewicz 134146ff15a6SArtur Paszkiewicz assert(str != NULL); 134246ff15a6SArtur Paszkiewicz 13430ea6e36aSArtur Paszkiewicz for (i = 0; i < RAID_BDEV_STATE_MAX; i++) { 13440ea6e36aSArtur Paszkiewicz if (strcasecmp(g_raid_state_names[i], str) == 0) { 13450ea6e36aSArtur Paszkiewicz break; 134646ff15a6SArtur Paszkiewicz } 134746ff15a6SArtur Paszkiewicz } 134846ff15a6SArtur Paszkiewicz 13490ea6e36aSArtur Paszkiewicz return i; 135046ff15a6SArtur Paszkiewicz } 135146ff15a6SArtur Paszkiewicz 135246ff15a6SArtur Paszkiewicz const char * 135346ff15a6SArtur Paszkiewicz raid_bdev_state_to_str(enum raid_bdev_state state) 135446ff15a6SArtur Paszkiewicz { 13550ea6e36aSArtur Paszkiewicz if (state >= RAID_BDEV_STATE_MAX) { 135646ff15a6SArtur Paszkiewicz return ""; 135746ff15a6SArtur Paszkiewicz } 135846ff15a6SArtur Paszkiewicz 13590ea6e36aSArtur Paszkiewicz return g_raid_state_names[state]; 13600ea6e36aSArtur Paszkiewicz } 13610ea6e36aSArtur Paszkiewicz 136250d58ff3SArtur Paszkiewicz const char * 136350d58ff3SArtur Paszkiewicz raid_bdev_process_to_str(enum raid_process_type value) 136450d58ff3SArtur Paszkiewicz { 136550d58ff3SArtur Paszkiewicz if (value >= RAID_PROCESS_MAX) { 136650d58ff3SArtur Paszkiewicz return ""; 136750d58ff3SArtur Paszkiewicz } 136850d58ff3SArtur Paszkiewicz 136950d58ff3SArtur Paszkiewicz return g_raid_process_type_names[value]; 137050d58ff3SArtur Paszkiewicz } 137150d58ff3SArtur Paszkiewicz 137207fe6a43SSeth Howell /* 137307fe6a43SSeth Howell * brief: 137407fe6a43SSeth Howell * raid_bdev_fini_start is called when bdev layer is starting the 137507fe6a43SSeth Howell * shutdown process 137607fe6a43SSeth Howell * params: 137707fe6a43SSeth Howell * none 137807fe6a43SSeth Howell * returns: 137907fe6a43SSeth Howell * none 138007fe6a43SSeth Howell */ 138107fe6a43SSeth Howell static void 138207fe6a43SSeth Howell raid_bdev_fini_start(void) 138307fe6a43SSeth Howell { 1384f8465ae4SSebastian Brzezinka struct raid_bdev *raid_bdev; 1385f8465ae4SSebastian Brzezinka struct raid_base_bdev_info *base_info; 1386f8465ae4SSebastian Brzezinka 13872172c432STomasz Zawadzki SPDK_DEBUGLOG(bdev_raid, "raid_bdev_fini_start\n"); 1388f8465ae4SSebastian Brzezinka 1389f8465ae4SSebastian Brzezinka TAILQ_FOREACH(raid_bdev, &g_raid_bdev_list, global_link) { 1390f8465ae4SSebastian Brzezinka if (raid_bdev->state != RAID_BDEV_STATE_ONLINE) { 1391f8465ae4SSebastian Brzezinka RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) { 1392f8465ae4SSebastian Brzezinka raid_bdev_free_base_bdev_resource(base_info); 1393f8465ae4SSebastian Brzezinka } 1394f8465ae4SSebastian Brzezinka } 1395f8465ae4SSebastian Brzezinka } 1396f8465ae4SSebastian Brzezinka 139707fe6a43SSeth Howell g_shutdown_started = true; 139807fe6a43SSeth Howell } 139907fe6a43SSeth Howell 140007fe6a43SSeth Howell /* 140107fe6a43SSeth Howell * brief: 140207fe6a43SSeth Howell * raid_bdev_exit is called on raid bdev module exit time by bdev layer 140307fe6a43SSeth Howell * params: 140407fe6a43SSeth Howell * none 140507fe6a43SSeth Howell * returns: 140607fe6a43SSeth Howell * none 140707fe6a43SSeth Howell */ 140807fe6a43SSeth Howell static void 140907fe6a43SSeth Howell raid_bdev_exit(void) 141007fe6a43SSeth Howell { 1411dccdd1e5SArtur Paszkiewicz struct raid_bdev *raid_bdev, *tmp; 141295a04949SArtur Paszkiewicz 14132172c432STomasz Zawadzki SPDK_DEBUGLOG(bdev_raid, "raid_bdev_exit\n"); 1414dccdd1e5SArtur Paszkiewicz 1415dccdd1e5SArtur Paszkiewicz TAILQ_FOREACH_SAFE(raid_bdev, &g_raid_bdev_list, global_link, tmp) { 1416dccdd1e5SArtur Paszkiewicz raid_bdev_cleanup_and_free(raid_bdev); 141795a04949SArtur Paszkiewicz } 141807fe6a43SSeth Howell } 141907fe6a43SSeth Howell 1420f39350beSArtur Paszkiewicz static void 1421f39350beSArtur Paszkiewicz raid_bdev_opts_config_json(struct spdk_json_write_ctx *w) 1422f39350beSArtur Paszkiewicz { 1423f39350beSArtur Paszkiewicz spdk_json_write_object_begin(w); 1424f39350beSArtur Paszkiewicz 1425f39350beSArtur Paszkiewicz spdk_json_write_named_string(w, "method", "bdev_raid_set_options"); 1426f39350beSArtur Paszkiewicz 1427f39350beSArtur Paszkiewicz spdk_json_write_named_object_begin(w, "params"); 1428f39350beSArtur Paszkiewicz spdk_json_write_named_uint32(w, "process_window_size_kb", g_opts.process_window_size_kb); 142989fd1730Sxupeng9 spdk_json_write_named_uint32(w, "process_max_bandwidth_mb_sec", 143089fd1730Sxupeng9 g_opts.process_max_bandwidth_mb_sec); 1431f39350beSArtur Paszkiewicz spdk_json_write_object_end(w); 1432f39350beSArtur Paszkiewicz 1433f39350beSArtur Paszkiewicz spdk_json_write_object_end(w); 1434f39350beSArtur Paszkiewicz } 1435f39350beSArtur Paszkiewicz 1436f39350beSArtur Paszkiewicz static int 1437f39350beSArtur Paszkiewicz raid_bdev_config_json(struct spdk_json_write_ctx *w) 1438f39350beSArtur Paszkiewicz { 1439f39350beSArtur Paszkiewicz raid_bdev_opts_config_json(w); 1440f39350beSArtur Paszkiewicz 1441f39350beSArtur Paszkiewicz return 0; 1442f39350beSArtur Paszkiewicz } 1443f39350beSArtur Paszkiewicz 144407fe6a43SSeth Howell /* 144507fe6a43SSeth Howell * brief: 144607fe6a43SSeth Howell * raid_bdev_get_ctx_size is used to return the context size of bdev_io for raid 144707fe6a43SSeth Howell * module 144807fe6a43SSeth Howell * params: 144907fe6a43SSeth Howell * none 145007fe6a43SSeth Howell * returns: 145107fe6a43SSeth Howell * size of spdk_bdev_io context for raid 145207fe6a43SSeth Howell */ 145307fe6a43SSeth Howell static int 145407fe6a43SSeth Howell raid_bdev_get_ctx_size(void) 145507fe6a43SSeth Howell { 14562172c432STomasz Zawadzki SPDK_DEBUGLOG(bdev_raid, "raid_bdev_get_ctx_size\n"); 145707fe6a43SSeth Howell return sizeof(struct raid_bdev_io); 145807fe6a43SSeth Howell } 145907fe6a43SSeth Howell 146007fe6a43SSeth Howell static struct spdk_bdev_module g_raid_if = { 146107fe6a43SSeth Howell .name = "raid", 146207fe6a43SSeth Howell .module_init = raid_bdev_init, 146307fe6a43SSeth Howell .fini_start = raid_bdev_fini_start, 146407fe6a43SSeth Howell .module_fini = raid_bdev_exit, 1465f39350beSArtur Paszkiewicz .config_json = raid_bdev_config_json, 146607fe6a43SSeth Howell .get_ctx_size = raid_bdev_get_ctx_size, 14678a6bb6a8SArtur Paszkiewicz .examine_disk = raid_bdev_examine, 146807fe6a43SSeth Howell .async_init = false, 146907fe6a43SSeth Howell .async_fini = false, 147007fe6a43SSeth Howell }; 147107fe6a43SSeth Howell SPDK_BDEV_MODULE_REGISTER(raid, &g_raid_if) 147207fe6a43SSeth Howell 147307fe6a43SSeth Howell /* 147407fe6a43SSeth Howell * brief: 147507fe6a43SSeth Howell * raid_bdev_init is the initialization function for raid bdev module 147607fe6a43SSeth Howell * params: 147707fe6a43SSeth Howell * none 147807fe6a43SSeth Howell * returns: 147907fe6a43SSeth Howell * 0 - success 148007fe6a43SSeth Howell * non zero - failure 148107fe6a43SSeth Howell */ 148207fe6a43SSeth Howell static int 148307fe6a43SSeth Howell raid_bdev_init(void) 148407fe6a43SSeth Howell { 148507fe6a43SSeth Howell return 0; 148607fe6a43SSeth Howell } 148707fe6a43SSeth Howell 148877b8f7b6SArtur Paszkiewicz static int 148977b8f7b6SArtur Paszkiewicz _raid_bdev_create(const char *name, uint32_t strip_size, uint8_t num_base_bdevs, 1490deed7d2fSArtur Paszkiewicz enum raid_level level, bool superblock_enabled, const struct spdk_uuid *uuid, 1491deed7d2fSArtur Paszkiewicz struct raid_bdev **raid_bdev_out) 149207fe6a43SSeth Howell { 149307fe6a43SSeth Howell struct raid_bdev *raid_bdev; 149407fe6a43SSeth Howell struct spdk_bdev *raid_bdev_gen; 14950a5194faSArtur Paszkiewicz struct raid_bdev_module *module; 149626861b70SArtur Paszkiewicz struct raid_base_bdev_info *base_info; 1497ad94094fSKrzysztof Smolinski uint8_t min_operational; 14980a5194faSArtur Paszkiewicz 149977b8f7b6SArtur Paszkiewicz if (strnlen(name, RAID_BDEV_SB_NAME_SIZE) == RAID_BDEV_SB_NAME_SIZE) { 150077b8f7b6SArtur Paszkiewicz SPDK_ERRLOG("Raid bdev name '%s' exceeds %d characters\n", name, RAID_BDEV_SB_NAME_SIZE - 1); 150177b8f7b6SArtur Paszkiewicz return -EINVAL; 150277b8f7b6SArtur Paszkiewicz } 150377b8f7b6SArtur Paszkiewicz 1504dccdd1e5SArtur Paszkiewicz if (raid_bdev_find_by_name(name) != NULL) { 1505dccdd1e5SArtur Paszkiewicz SPDK_ERRLOG("Duplicate raid bdev name found: %s\n", name); 1506dccdd1e5SArtur Paszkiewicz return -EEXIST; 1507dccdd1e5SArtur Paszkiewicz } 1508dccdd1e5SArtur Paszkiewicz 1509208f21cdSKrzysztof Smolinski if (level == RAID1) { 1510208f21cdSKrzysztof Smolinski if (strip_size != 0) { 1511208f21cdSKrzysztof Smolinski SPDK_ERRLOG("Strip size is not supported by raid1\n"); 1512208f21cdSKrzysztof Smolinski return -EINVAL; 1513208f21cdSKrzysztof Smolinski } 1514208f21cdSKrzysztof Smolinski } else if (spdk_u32_is_pow2(strip_size) == false) { 1515dccdd1e5SArtur Paszkiewicz SPDK_ERRLOG("Invalid strip size %" PRIu32 "\n", strip_size); 1516dccdd1e5SArtur Paszkiewicz return -EINVAL; 1517dccdd1e5SArtur Paszkiewicz } 1518dccdd1e5SArtur Paszkiewicz 1519dccdd1e5SArtur Paszkiewicz module = raid_bdev_module_find(level); 15200a5194faSArtur Paszkiewicz if (module == NULL) { 1521dccdd1e5SArtur Paszkiewicz SPDK_ERRLOG("Unsupported raid level '%d'\n", level); 15220a5194faSArtur Paszkiewicz return -EINVAL; 15230a5194faSArtur Paszkiewicz } 15240a5194faSArtur Paszkiewicz 15250a5194faSArtur Paszkiewicz assert(module->base_bdevs_min != 0); 1526dccdd1e5SArtur Paszkiewicz if (num_base_bdevs < module->base_bdevs_min) { 15270a5194faSArtur Paszkiewicz SPDK_ERRLOG("At least %u base devices required for %s\n", 15280a5194faSArtur Paszkiewicz module->base_bdevs_min, 1529dccdd1e5SArtur Paszkiewicz raid_bdev_level_to_str(level)); 15300a5194faSArtur Paszkiewicz return -EINVAL; 15310a5194faSArtur Paszkiewicz } 153207fe6a43SSeth Howell 1533ad94094fSKrzysztof Smolinski switch (module->base_bdevs_constraint.type) { 1534ad94094fSKrzysztof Smolinski case CONSTRAINT_MAX_BASE_BDEVS_REMOVED: 1535ad94094fSKrzysztof Smolinski min_operational = num_base_bdevs - module->base_bdevs_constraint.value; 1536ad94094fSKrzysztof Smolinski break; 1537ad94094fSKrzysztof Smolinski case CONSTRAINT_MIN_BASE_BDEVS_OPERATIONAL: 1538ad94094fSKrzysztof Smolinski min_operational = module->base_bdevs_constraint.value; 1539ad94094fSKrzysztof Smolinski break; 1540ad94094fSKrzysztof Smolinski case CONSTRAINT_UNSET: 1541ad94094fSKrzysztof Smolinski if (module->base_bdevs_constraint.value != 0) { 1542ad94094fSKrzysztof Smolinski SPDK_ERRLOG("Unexpected constraint value '%u' provided for raid bdev '%s'.\n", 1543ad94094fSKrzysztof Smolinski (uint8_t)module->base_bdevs_constraint.value, name); 1544ad94094fSKrzysztof Smolinski return -EINVAL; 1545ad94094fSKrzysztof Smolinski } 1546ad94094fSKrzysztof Smolinski min_operational = num_base_bdevs; 1547ad94094fSKrzysztof Smolinski break; 1548ad94094fSKrzysztof Smolinski default: 1549ad94094fSKrzysztof Smolinski SPDK_ERRLOG("Unrecognised constraint type '%u' in module for raid level '%s'.\n", 1550ad94094fSKrzysztof Smolinski (uint8_t)module->base_bdevs_constraint.type, 1551ad94094fSKrzysztof Smolinski raid_bdev_level_to_str(module->level)); 1552ad94094fSKrzysztof Smolinski return -EINVAL; 1553ad94094fSKrzysztof Smolinski }; 1554ad94094fSKrzysztof Smolinski 1555ad94094fSKrzysztof Smolinski if (min_operational == 0 || min_operational > num_base_bdevs) { 1556ad94094fSKrzysztof Smolinski SPDK_ERRLOG("Wrong constraint value for raid level '%s'.\n", 1557ad94094fSKrzysztof Smolinski raid_bdev_level_to_str(module->level)); 1558ad94094fSKrzysztof Smolinski return -EINVAL; 1559ad94094fSKrzysztof Smolinski } 1560ad94094fSKrzysztof Smolinski 156107fe6a43SSeth Howell raid_bdev = calloc(1, sizeof(*raid_bdev)); 156207fe6a43SSeth Howell if (!raid_bdev) { 156307fe6a43SSeth Howell SPDK_ERRLOG("Unable to allocate memory for raid bdev\n"); 156407fe6a43SSeth Howell return -ENOMEM; 156507fe6a43SSeth Howell } 156607fe6a43SSeth Howell 15670a5194faSArtur Paszkiewicz raid_bdev->module = module; 1568dccdd1e5SArtur Paszkiewicz raid_bdev->num_base_bdevs = num_base_bdevs; 156907fe6a43SSeth Howell raid_bdev->base_bdev_info = calloc(raid_bdev->num_base_bdevs, 157007fe6a43SSeth Howell sizeof(struct raid_base_bdev_info)); 157107fe6a43SSeth Howell if (!raid_bdev->base_bdev_info) { 157207fe6a43SSeth Howell SPDK_ERRLOG("Unable able to allocate base bdev info\n"); 1573fbdb05f0SArtur Paszkiewicz raid_bdev_free(raid_bdev); 157407fe6a43SSeth Howell return -ENOMEM; 157507fe6a43SSeth Howell } 157607fe6a43SSeth Howell 157726861b70SArtur Paszkiewicz RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) { 157826861b70SArtur Paszkiewicz base_info->raid_bdev = raid_bdev; 157926861b70SArtur Paszkiewicz } 158026861b70SArtur Paszkiewicz 158107fe6a43SSeth Howell /* strip_size_kb is from the rpc param. strip_size is in blocks and used 158217f7cf9bSpaul luse * internally and set later. 158307fe6a43SSeth Howell */ 158407fe6a43SSeth Howell raid_bdev->strip_size = 0; 1585dccdd1e5SArtur Paszkiewicz raid_bdev->strip_size_kb = strip_size; 158607fe6a43SSeth Howell raid_bdev->state = RAID_BDEV_STATE_CONFIGURING; 1587dccdd1e5SArtur Paszkiewicz raid_bdev->level = level; 1588ad94094fSKrzysztof Smolinski raid_bdev->min_base_bdevs_operational = min_operational; 15893bb8256aSArtur Paszkiewicz raid_bdev->superblock_enabled = superblock_enabled; 159077b8f7b6SArtur Paszkiewicz 159107fe6a43SSeth Howell raid_bdev_gen = &raid_bdev->bdev; 159207fe6a43SSeth Howell 1593dccdd1e5SArtur Paszkiewicz raid_bdev_gen->name = strdup(name); 159407fe6a43SSeth Howell if (!raid_bdev_gen->name) { 159507fe6a43SSeth Howell SPDK_ERRLOG("Unable to allocate name for raid\n"); 1596fbdb05f0SArtur Paszkiewicz raid_bdev_free(raid_bdev); 159707fe6a43SSeth Howell return -ENOMEM; 159807fe6a43SSeth Howell } 159907fe6a43SSeth Howell 160007fe6a43SSeth Howell raid_bdev_gen->product_name = "Raid Volume"; 160107fe6a43SSeth Howell raid_bdev_gen->ctxt = raid_bdev; 160207fe6a43SSeth Howell raid_bdev_gen->fn_table = &g_raid_bdev_fn_table; 160307fe6a43SSeth Howell raid_bdev_gen->module = &g_raid_if; 160407fe6a43SSeth Howell raid_bdev_gen->write_cache = 0; 16051db41324SKrzysztof Karas spdk_uuid_copy(&raid_bdev_gen->uuid, uuid); 16061db41324SKrzysztof Karas 160707fe6a43SSeth Howell TAILQ_INSERT_TAIL(&g_raid_bdev_list, raid_bdev, global_link); 160807fe6a43SSeth Howell 1609dccdd1e5SArtur Paszkiewicz *raid_bdev_out = raid_bdev; 161007fe6a43SSeth Howell 161107fe6a43SSeth Howell return 0; 161207fe6a43SSeth Howell } 161307fe6a43SSeth Howell 161407fe6a43SSeth Howell /* 161507fe6a43SSeth Howell * brief: 161677b8f7b6SArtur Paszkiewicz * raid_bdev_create allocates raid bdev based on passed configuration 161777b8f7b6SArtur Paszkiewicz * params: 161877b8f7b6SArtur Paszkiewicz * name - name for raid bdev 161977b8f7b6SArtur Paszkiewicz * strip_size - strip size in KB 162077b8f7b6SArtur Paszkiewicz * num_base_bdevs - number of base bdevs 162177b8f7b6SArtur Paszkiewicz * level - raid level 162277b8f7b6SArtur Paszkiewicz * superblock_enabled - true if raid should have superblock 162377b8f7b6SArtur Paszkiewicz * uuid - uuid to set for the bdev 162477b8f7b6SArtur Paszkiewicz * raid_bdev_out - the created raid bdev 162577b8f7b6SArtur Paszkiewicz * returns: 162677b8f7b6SArtur Paszkiewicz * 0 - success 162777b8f7b6SArtur Paszkiewicz * non zero - failure 162877b8f7b6SArtur Paszkiewicz */ 162977b8f7b6SArtur Paszkiewicz int 163077b8f7b6SArtur Paszkiewicz raid_bdev_create(const char *name, uint32_t strip_size, uint8_t num_base_bdevs, 163177b8f7b6SArtur Paszkiewicz enum raid_level level, bool superblock_enabled, const struct spdk_uuid *uuid, 163277b8f7b6SArtur Paszkiewicz struct raid_bdev **raid_bdev_out) 163377b8f7b6SArtur Paszkiewicz { 163477b8f7b6SArtur Paszkiewicz struct raid_bdev *raid_bdev; 163577b8f7b6SArtur Paszkiewicz int rc; 163677b8f7b6SArtur Paszkiewicz 163777b8f7b6SArtur Paszkiewicz assert(uuid != NULL); 163877b8f7b6SArtur Paszkiewicz 163977b8f7b6SArtur Paszkiewicz rc = _raid_bdev_create(name, strip_size, num_base_bdevs, level, superblock_enabled, uuid, 164077b8f7b6SArtur Paszkiewicz &raid_bdev); 164177b8f7b6SArtur Paszkiewicz if (rc != 0) { 164277b8f7b6SArtur Paszkiewicz return rc; 164377b8f7b6SArtur Paszkiewicz } 164477b8f7b6SArtur Paszkiewicz 164577b8f7b6SArtur Paszkiewicz if (superblock_enabled && spdk_uuid_is_null(uuid)) { 164677b8f7b6SArtur Paszkiewicz /* we need to have the uuid to store in the superblock before the bdev is registered */ 164777b8f7b6SArtur Paszkiewicz spdk_uuid_generate(&raid_bdev->bdev.uuid); 164877b8f7b6SArtur Paszkiewicz } 164977b8f7b6SArtur Paszkiewicz 1650255d0786SArtur Paszkiewicz raid_bdev->num_base_bdevs_operational = num_base_bdevs; 1651255d0786SArtur Paszkiewicz 165277b8f7b6SArtur Paszkiewicz *raid_bdev_out = raid_bdev; 165377b8f7b6SArtur Paszkiewicz 165477b8f7b6SArtur Paszkiewicz return 0; 165577b8f7b6SArtur Paszkiewicz } 165677b8f7b6SArtur Paszkiewicz 165777b8f7b6SArtur Paszkiewicz static void 16589d2b7b41SArtur Paszkiewicz _raid_bdev_unregistering_cont(void *ctx) 16599d2b7b41SArtur Paszkiewicz { 16609d2b7b41SArtur Paszkiewicz struct raid_bdev *raid_bdev = ctx; 16619d2b7b41SArtur Paszkiewicz 16629d2b7b41SArtur Paszkiewicz spdk_bdev_close(raid_bdev->self_desc); 16639d2b7b41SArtur Paszkiewicz raid_bdev->self_desc = NULL; 16649d2b7b41SArtur Paszkiewicz } 16659d2b7b41SArtur Paszkiewicz 16669d2b7b41SArtur Paszkiewicz static void 16679d2b7b41SArtur Paszkiewicz raid_bdev_unregistering_cont(void *ctx) 16689d2b7b41SArtur Paszkiewicz { 16699d2b7b41SArtur Paszkiewicz spdk_thread_exec_msg(spdk_thread_get_app_thread(), _raid_bdev_unregistering_cont, ctx); 16709d2b7b41SArtur Paszkiewicz } 16719d2b7b41SArtur Paszkiewicz 16729d2b7b41SArtur Paszkiewicz static int 16739d2b7b41SArtur Paszkiewicz raid_bdev_process_add_finish_action(struct raid_bdev_process *process, spdk_msg_fn cb, void *cb_ctx) 16749d2b7b41SArtur Paszkiewicz { 16759d2b7b41SArtur Paszkiewicz struct raid_process_finish_action *finish_action; 16769d2b7b41SArtur Paszkiewicz 16779d2b7b41SArtur Paszkiewicz assert(spdk_get_thread() == process->thread); 16789d2b7b41SArtur Paszkiewicz assert(process->state < RAID_PROCESS_STATE_STOPPED); 16799d2b7b41SArtur Paszkiewicz 16809d2b7b41SArtur Paszkiewicz finish_action = calloc(1, sizeof(*finish_action)); 16819d2b7b41SArtur Paszkiewicz if (finish_action == NULL) { 16829d2b7b41SArtur Paszkiewicz return -ENOMEM; 16839d2b7b41SArtur Paszkiewicz } 16849d2b7b41SArtur Paszkiewicz 16859d2b7b41SArtur Paszkiewicz finish_action->cb = cb; 16869d2b7b41SArtur Paszkiewicz finish_action->cb_ctx = cb_ctx; 16879d2b7b41SArtur Paszkiewicz 16889d2b7b41SArtur Paszkiewicz TAILQ_INSERT_TAIL(&process->finish_actions, finish_action, link); 16899d2b7b41SArtur Paszkiewicz 16909d2b7b41SArtur Paszkiewicz return 0; 16919d2b7b41SArtur Paszkiewicz } 16929d2b7b41SArtur Paszkiewicz 16939d2b7b41SArtur Paszkiewicz static void 16949d2b7b41SArtur Paszkiewicz raid_bdev_unregistering_stop_process(void *ctx) 16959d2b7b41SArtur Paszkiewicz { 16969d2b7b41SArtur Paszkiewicz struct raid_bdev_process *process = ctx; 16979d2b7b41SArtur Paszkiewicz struct raid_bdev *raid_bdev = process->raid_bdev; 16989d2b7b41SArtur Paszkiewicz int rc; 16999d2b7b41SArtur Paszkiewicz 17009d2b7b41SArtur Paszkiewicz process->state = RAID_PROCESS_STATE_STOPPING; 17019d2b7b41SArtur Paszkiewicz if (process->status == 0) { 17029d2b7b41SArtur Paszkiewicz process->status = -ECANCELED; 17039d2b7b41SArtur Paszkiewicz } 17049d2b7b41SArtur Paszkiewicz 17059d2b7b41SArtur Paszkiewicz rc = raid_bdev_process_add_finish_action(process, raid_bdev_unregistering_cont, raid_bdev); 17069d2b7b41SArtur Paszkiewicz if (rc != 0) { 17079d2b7b41SArtur Paszkiewicz SPDK_ERRLOG("Failed to add raid bdev '%s' process finish action: %s\n", 17089d2b7b41SArtur Paszkiewicz raid_bdev->bdev.name, spdk_strerror(-rc)); 17099d2b7b41SArtur Paszkiewicz } 17109d2b7b41SArtur Paszkiewicz } 17119d2b7b41SArtur Paszkiewicz 17129d2b7b41SArtur Paszkiewicz static void 17139d2b7b41SArtur Paszkiewicz raid_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *event_ctx) 17149d2b7b41SArtur Paszkiewicz { 17159d2b7b41SArtur Paszkiewicz struct raid_bdev *raid_bdev = event_ctx; 17169d2b7b41SArtur Paszkiewicz 17179b61146fSArtur Paszkiewicz if (type == SPDK_BDEV_EVENT_REMOVE) { 17189d2b7b41SArtur Paszkiewicz if (raid_bdev->process != NULL) { 17199d2b7b41SArtur Paszkiewicz spdk_thread_send_msg(raid_bdev->process->thread, raid_bdev_unregistering_stop_process, 17209d2b7b41SArtur Paszkiewicz raid_bdev->process); 17219d2b7b41SArtur Paszkiewicz } else { 17229d2b7b41SArtur Paszkiewicz raid_bdev_unregistering_cont(raid_bdev); 17239d2b7b41SArtur Paszkiewicz } 17249d2b7b41SArtur Paszkiewicz } 17259d2b7b41SArtur Paszkiewicz } 17269d2b7b41SArtur Paszkiewicz 17279d2b7b41SArtur Paszkiewicz static void 172877b8f7b6SArtur Paszkiewicz raid_bdev_configure_cont(struct raid_bdev *raid_bdev) 172977b8f7b6SArtur Paszkiewicz { 173077b8f7b6SArtur Paszkiewicz struct spdk_bdev *raid_bdev_gen = &raid_bdev->bdev; 173177b8f7b6SArtur Paszkiewicz int rc; 173277b8f7b6SArtur Paszkiewicz 173377b8f7b6SArtur Paszkiewicz raid_bdev->state = RAID_BDEV_STATE_ONLINE; 173477b8f7b6SArtur Paszkiewicz SPDK_DEBUGLOG(bdev_raid, "io device register %p\n", raid_bdev); 173577b8f7b6SArtur Paszkiewicz SPDK_DEBUGLOG(bdev_raid, "blockcnt %" PRIu64 ", blocklen %u\n", 173677b8f7b6SArtur Paszkiewicz raid_bdev_gen->blockcnt, raid_bdev_gen->blocklen); 173777b8f7b6SArtur Paszkiewicz spdk_io_device_register(raid_bdev, raid_bdev_create_cb, raid_bdev_destroy_cb, 173877b8f7b6SArtur Paszkiewicz sizeof(struct raid_bdev_io_channel), 173977b8f7b6SArtur Paszkiewicz raid_bdev_gen->name); 174077b8f7b6SArtur Paszkiewicz rc = spdk_bdev_register(raid_bdev_gen); 174177b8f7b6SArtur Paszkiewicz if (rc != 0) { 17429d2b7b41SArtur Paszkiewicz SPDK_ERRLOG("Failed to register raid bdev '%s': %s\n", 17439d2b7b41SArtur Paszkiewicz raid_bdev_gen->name, spdk_strerror(-rc)); 17445558f3f5SArtur Paszkiewicz goto out; 17459d2b7b41SArtur Paszkiewicz } 17469d2b7b41SArtur Paszkiewicz 17479d2b7b41SArtur Paszkiewicz /* 17489d2b7b41SArtur Paszkiewicz * Open the bdev internally to delay unregistering if we need to stop a background process 17499d2b7b41SArtur Paszkiewicz * first. The process may still need to unquiesce a range but it will fail because the 17509d2b7b41SArtur Paszkiewicz * bdev's internal.spinlock is destroyed by the time the destruct callback is reached. 17519d2b7b41SArtur Paszkiewicz * During application shutdown, bdevs automatically get unregistered by the bdev layer 17529d2b7b41SArtur Paszkiewicz * so this is the only way currently to do this correctly. 17539d2b7b41SArtur Paszkiewicz * TODO: try to handle this correctly in bdev layer instead. 17549d2b7b41SArtur Paszkiewicz */ 17559d2b7b41SArtur Paszkiewicz rc = spdk_bdev_open_ext(raid_bdev_gen->name, false, raid_bdev_event_cb, raid_bdev, 17569d2b7b41SArtur Paszkiewicz &raid_bdev->self_desc); 17579d2b7b41SArtur Paszkiewicz if (rc != 0) { 17589d2b7b41SArtur Paszkiewicz SPDK_ERRLOG("Failed to open raid bdev '%s': %s\n", 17599d2b7b41SArtur Paszkiewicz raid_bdev_gen->name, spdk_strerror(-rc)); 17609d2b7b41SArtur Paszkiewicz spdk_bdev_unregister(raid_bdev_gen, NULL, NULL); 17615558f3f5SArtur Paszkiewicz goto out; 17629d2b7b41SArtur Paszkiewicz } 17639d2b7b41SArtur Paszkiewicz 17649d2b7b41SArtur Paszkiewicz SPDK_DEBUGLOG(bdev_raid, "raid bdev generic %p\n", raid_bdev_gen); 17659d2b7b41SArtur Paszkiewicz SPDK_DEBUGLOG(bdev_raid, "raid bdev is created with name %s, raid_bdev %p\n", 17669d2b7b41SArtur Paszkiewicz raid_bdev_gen->name, raid_bdev); 17675558f3f5SArtur Paszkiewicz out: 17685558f3f5SArtur Paszkiewicz if (rc != 0) { 176977b8f7b6SArtur Paszkiewicz if (raid_bdev->module->stop != NULL) { 177077b8f7b6SArtur Paszkiewicz raid_bdev->module->stop(raid_bdev); 177177b8f7b6SArtur Paszkiewicz } 177277b8f7b6SArtur Paszkiewicz spdk_io_device_unregister(raid_bdev, NULL); 177377b8f7b6SArtur Paszkiewicz raid_bdev->state = RAID_BDEV_STATE_CONFIGURING; 177477b8f7b6SArtur Paszkiewicz } 177577b8f7b6SArtur Paszkiewicz 17765558f3f5SArtur Paszkiewicz if (raid_bdev->configure_cb != NULL) { 17775558f3f5SArtur Paszkiewicz raid_bdev->configure_cb(raid_bdev->configure_cb_ctx, rc); 17785558f3f5SArtur Paszkiewicz raid_bdev->configure_cb = NULL; 17795558f3f5SArtur Paszkiewicz } 17805558f3f5SArtur Paszkiewicz } 17815558f3f5SArtur Paszkiewicz 178277b8f7b6SArtur Paszkiewicz static void 178377b8f7b6SArtur Paszkiewicz raid_bdev_configure_write_sb_cb(int status, struct raid_bdev *raid_bdev, void *ctx) 178477b8f7b6SArtur Paszkiewicz { 178577b8f7b6SArtur Paszkiewicz if (status == 0) { 178677b8f7b6SArtur Paszkiewicz raid_bdev_configure_cont(raid_bdev); 178777b8f7b6SArtur Paszkiewicz } else { 178877b8f7b6SArtur Paszkiewicz SPDK_ERRLOG("Failed to write raid bdev '%s' superblock: %s\n", 178977b8f7b6SArtur Paszkiewicz raid_bdev->bdev.name, spdk_strerror(-status)); 179077b8f7b6SArtur Paszkiewicz if (raid_bdev->module->stop != NULL) { 179177b8f7b6SArtur Paszkiewicz raid_bdev->module->stop(raid_bdev); 179277b8f7b6SArtur Paszkiewicz } 17935558f3f5SArtur Paszkiewicz if (raid_bdev->configure_cb != NULL) { 17945558f3f5SArtur Paszkiewicz raid_bdev->configure_cb(raid_bdev->configure_cb_ctx, status); 17955558f3f5SArtur Paszkiewicz raid_bdev->configure_cb = NULL; 17965558f3f5SArtur Paszkiewicz } 179777b8f7b6SArtur Paszkiewicz } 179877b8f7b6SArtur Paszkiewicz } 179977b8f7b6SArtur Paszkiewicz 1800357c038cSKrzysztof Smolinski /* 1801357c038cSKrzysztof Smolinski * brief: 180207fe6a43SSeth Howell * If raid bdev config is complete, then only register the raid bdev to 180307fe6a43SSeth Howell * bdev layer and remove this raid bdev from configuring list and 180407fe6a43SSeth Howell * insert the raid bdev to configured list 180507fe6a43SSeth Howell * params: 180607fe6a43SSeth Howell * raid_bdev - pointer to raid bdev 180707fe6a43SSeth Howell * returns: 180807fe6a43SSeth Howell * 0 - success 180907fe6a43SSeth Howell * non zero - failure 181007fe6a43SSeth Howell */ 181107fe6a43SSeth Howell static int 18125558f3f5SArtur Paszkiewicz raid_bdev_configure(struct raid_bdev *raid_bdev, raid_bdev_configure_cb cb, void *cb_ctx) 181307fe6a43SSeth Howell { 1814bb374988SArtur Paszkiewicz uint32_t data_block_size = spdk_bdev_get_data_block_size(&raid_bdev->bdev); 1815895d8b56SArtur Paszkiewicz int rc; 181607fe6a43SSeth Howell 181794ea8754SArtur Paszkiewicz assert(raid_bdev->state == RAID_BDEV_STATE_CONFIGURING); 1818255d0786SArtur Paszkiewicz assert(raid_bdev->num_base_bdevs_discovered == raid_bdev->num_base_bdevs_operational); 1819895d8b56SArtur Paszkiewicz assert(raid_bdev->bdev.blocklen > 0); 182007fe6a43SSeth Howell 182107fe6a43SSeth Howell /* The strip_size_kb is read in from user in KB. Convert to blocks here for 182207fe6a43SSeth Howell * internal use. 182307fe6a43SSeth Howell */ 1824bb374988SArtur Paszkiewicz raid_bdev->strip_size = (raid_bdev->strip_size_kb * 1024) / data_block_size; 182531ce6cd8SArtur Paszkiewicz if (raid_bdev->strip_size == 0 && raid_bdev->level != RAID1) { 182631ce6cd8SArtur Paszkiewicz SPDK_ERRLOG("Strip size cannot be smaller than the device block size\n"); 182731ce6cd8SArtur Paszkiewicz return -EINVAL; 182831ce6cd8SArtur Paszkiewicz } 182907fe6a43SSeth Howell raid_bdev->strip_size_shift = spdk_u32log2(raid_bdev->strip_size); 1830357c038cSKrzysztof Smolinski 18310b4ca522SArtur Paszkiewicz rc = raid_bdev->module->start(raid_bdev); 18320b4ca522SArtur Paszkiewicz if (rc != 0) { 18330b4ca522SArtur Paszkiewicz SPDK_ERRLOG("raid module startup callback failed\n"); 18340b4ca522SArtur Paszkiewicz return rc; 183507fe6a43SSeth Howell } 183677b8f7b6SArtur Paszkiewicz 18375558f3f5SArtur Paszkiewicz assert(raid_bdev->configure_cb == NULL); 18385558f3f5SArtur Paszkiewicz raid_bdev->configure_cb = cb; 18395558f3f5SArtur Paszkiewicz raid_bdev->configure_cb_ctx = cb_ctx; 18405558f3f5SArtur Paszkiewicz 18413bb8256aSArtur Paszkiewicz if (raid_bdev->superblock_enabled) { 1842c25b80e2SArtur Paszkiewicz if (raid_bdev->sb == NULL) { 1843c25b80e2SArtur Paszkiewicz rc = raid_bdev_alloc_superblock(raid_bdev, data_block_size); 1844c25b80e2SArtur Paszkiewicz if (rc == 0) { 184577b8f7b6SArtur Paszkiewicz raid_bdev_init_superblock(raid_bdev); 1846c25b80e2SArtur Paszkiewicz } 18478a6bb6a8SArtur Paszkiewicz } else { 18488a6bb6a8SArtur Paszkiewicz assert(spdk_uuid_compare(&raid_bdev->sb->uuid, &raid_bdev->bdev.uuid) == 0); 1849bb374988SArtur Paszkiewicz if (raid_bdev->sb->block_size != data_block_size) { 18508a6bb6a8SArtur Paszkiewicz SPDK_ERRLOG("blocklen does not match value in superblock\n"); 18518a6bb6a8SArtur Paszkiewicz rc = -EINVAL; 18528a6bb6a8SArtur Paszkiewicz } 18538a6bb6a8SArtur Paszkiewicz if (raid_bdev->sb->raid_size != raid_bdev->bdev.blockcnt) { 18548a6bb6a8SArtur Paszkiewicz SPDK_ERRLOG("blockcnt does not match value in superblock\n"); 18558a6bb6a8SArtur Paszkiewicz rc = -EINVAL; 18568a6bb6a8SArtur Paszkiewicz } 1857c25b80e2SArtur Paszkiewicz } 1858c25b80e2SArtur Paszkiewicz 18598a6bb6a8SArtur Paszkiewicz if (rc != 0) { 18605558f3f5SArtur Paszkiewicz raid_bdev->configure_cb = NULL; 18618a6bb6a8SArtur Paszkiewicz if (raid_bdev->module->stop != NULL) { 18628a6bb6a8SArtur Paszkiewicz raid_bdev->module->stop(raid_bdev); 18638a6bb6a8SArtur Paszkiewicz } 18648a6bb6a8SArtur Paszkiewicz return rc; 18658a6bb6a8SArtur Paszkiewicz } 18668a6bb6a8SArtur Paszkiewicz 186777b8f7b6SArtur Paszkiewicz raid_bdev_write_superblock(raid_bdev, raid_bdev_configure_write_sb_cb, NULL); 186877b8f7b6SArtur Paszkiewicz } else { 186977b8f7b6SArtur Paszkiewicz raid_bdev_configure_cont(raid_bdev); 18700b4ca522SArtur Paszkiewicz } 187107fe6a43SSeth Howell 187207fe6a43SSeth Howell return 0; 187307fe6a43SSeth Howell } 187407fe6a43SSeth Howell 187507fe6a43SSeth Howell /* 187607fe6a43SSeth Howell * brief: 187707fe6a43SSeth Howell * If raid bdev is online and registered, change the bdev state to 187807fe6a43SSeth Howell * configuring and unregister this raid device. Queue this raid device 187907fe6a43SSeth Howell * in configuring list 188007fe6a43SSeth Howell * params: 188107fe6a43SSeth Howell * raid_bdev - pointer to raid bdev 188207fe6a43SSeth Howell * cb_fn - callback function 188307fe6a43SSeth Howell * cb_arg - argument to callback function 188407fe6a43SSeth Howell * returns: 188507fe6a43SSeth Howell * none 188607fe6a43SSeth Howell */ 188707fe6a43SSeth Howell static void 188807fe6a43SSeth Howell raid_bdev_deconfigure(struct raid_bdev *raid_bdev, raid_bdev_destruct_cb cb_fn, 188907fe6a43SSeth Howell void *cb_arg) 189007fe6a43SSeth Howell { 189107fe6a43SSeth Howell if (raid_bdev->state != RAID_BDEV_STATE_ONLINE) { 189207fe6a43SSeth Howell if (cb_fn) { 189307fe6a43SSeth Howell cb_fn(cb_arg, 0); 189407fe6a43SSeth Howell } 189507fe6a43SSeth Howell return; 189607fe6a43SSeth Howell } 189707fe6a43SSeth Howell 189807fe6a43SSeth Howell raid_bdev->state = RAID_BDEV_STATE_OFFLINE; 18991960ef16SJosh Soref SPDK_DEBUGLOG(bdev_raid, "raid bdev state changing from online to offline\n"); 190007fe6a43SSeth Howell 190107fe6a43SSeth Howell spdk_bdev_unregister(&raid_bdev->bdev, cb_fn, cb_arg); 190207fe6a43SSeth Howell } 190307fe6a43SSeth Howell 190407fe6a43SSeth Howell /* 190507fe6a43SSeth Howell * brief: 190626861b70SArtur Paszkiewicz * raid_bdev_find_base_info_by_bdev function finds the base bdev info by bdev. 190707fe6a43SSeth Howell * params: 190826861b70SArtur Paszkiewicz * base_bdev - pointer to base bdev 190907fe6a43SSeth Howell * returns: 191026861b70SArtur Paszkiewicz * base bdev info if found, otherwise NULL. 191107fe6a43SSeth Howell */ 191226861b70SArtur Paszkiewicz static struct raid_base_bdev_info * 191326861b70SArtur Paszkiewicz raid_bdev_find_base_info_by_bdev(struct spdk_bdev *base_bdev) 191407fe6a43SSeth Howell { 191507fe6a43SSeth Howell struct raid_bdev *raid_bdev; 1916a193dcb8SArtur Paszkiewicz struct raid_base_bdev_info *base_info; 191707fe6a43SSeth Howell 191807fe6a43SSeth Howell TAILQ_FOREACH(raid_bdev, &g_raid_bdev_list, global_link) { 1919a193dcb8SArtur Paszkiewicz RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) { 19208d1993a5SArtur Paszkiewicz if (base_info->desc != NULL && 19218d1993a5SArtur Paszkiewicz spdk_bdev_desc_get_bdev(base_info->desc) == base_bdev) { 192226861b70SArtur Paszkiewicz return base_info; 192307fe6a43SSeth Howell } 192407fe6a43SSeth Howell } 192507fe6a43SSeth Howell } 192607fe6a43SSeth Howell 192726861b70SArtur Paszkiewicz return NULL; 192807fe6a43SSeth Howell } 192907fe6a43SSeth Howell 1930b42cb0e5SArtur Paszkiewicz static void 19314cc10656SArtur Paszkiewicz raid_bdev_remove_base_bdev_done(struct raid_base_bdev_info *base_info, int status) 19324cc10656SArtur Paszkiewicz { 19332ea7b741SArtur Paszkiewicz struct raid_bdev *raid_bdev = base_info->raid_bdev; 19344cc10656SArtur Paszkiewicz 19352ea7b741SArtur Paszkiewicz assert(base_info->remove_scheduled); 19364cc10656SArtur Paszkiewicz base_info->remove_scheduled = false; 19372ea7b741SArtur Paszkiewicz 19382ea7b741SArtur Paszkiewicz if (status == 0) { 19392ea7b741SArtur Paszkiewicz raid_bdev->num_base_bdevs_operational--; 19402ea7b741SArtur Paszkiewicz if (raid_bdev->num_base_bdevs_operational < raid_bdev->min_base_bdevs_operational) { 19412ea7b741SArtur Paszkiewicz /* There is not enough base bdevs to keep the raid bdev operational. */ 19422ea7b741SArtur Paszkiewicz raid_bdev_deconfigure(raid_bdev, base_info->remove_cb, base_info->remove_cb_ctx); 19432ea7b741SArtur Paszkiewicz return; 19442ea7b741SArtur Paszkiewicz } 19452ea7b741SArtur Paszkiewicz } 19462ea7b741SArtur Paszkiewicz 19474cc10656SArtur Paszkiewicz if (base_info->remove_cb != NULL) { 19484cc10656SArtur Paszkiewicz base_info->remove_cb(base_info->remove_cb_ctx, status); 19494cc10656SArtur Paszkiewicz } 19504cc10656SArtur Paszkiewicz } 19514cc10656SArtur Paszkiewicz 19524cc10656SArtur Paszkiewicz static void 1953b42cb0e5SArtur Paszkiewicz raid_bdev_remove_base_bdev_on_unquiesced(void *ctx, int status) 1954b42cb0e5SArtur Paszkiewicz { 1955b42cb0e5SArtur Paszkiewicz struct raid_base_bdev_info *base_info = ctx; 1956b42cb0e5SArtur Paszkiewicz struct raid_bdev *raid_bdev = base_info->raid_bdev; 1957b42cb0e5SArtur Paszkiewicz 1958b42cb0e5SArtur Paszkiewicz if (status != 0) { 1959b42cb0e5SArtur Paszkiewicz SPDK_ERRLOG("Failed to unquiesce raid bdev %s: %s\n", 1960b42cb0e5SArtur Paszkiewicz raid_bdev->bdev.name, spdk_strerror(-status)); 1961b42cb0e5SArtur Paszkiewicz } 1962b42cb0e5SArtur Paszkiewicz 19634cc10656SArtur Paszkiewicz raid_bdev_remove_base_bdev_done(base_info, status); 1964b42cb0e5SArtur Paszkiewicz } 1965b42cb0e5SArtur Paszkiewicz 1966b42cb0e5SArtur Paszkiewicz static void 1967b42cb0e5SArtur Paszkiewicz raid_bdev_channel_remove_base_bdev(struct spdk_io_channel_iter *i) 1968b42cb0e5SArtur Paszkiewicz { 1969b42cb0e5SArtur Paszkiewicz struct raid_base_bdev_info *base_info = spdk_io_channel_iter_get_ctx(i); 1970b42cb0e5SArtur Paszkiewicz struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(i); 1971b42cb0e5SArtur Paszkiewicz struct raid_bdev_io_channel *raid_ch = spdk_io_channel_get_ctx(ch); 1972fd92e702SArtur Paszkiewicz uint8_t idx = raid_bdev_base_bdev_slot(base_info); 1973b42cb0e5SArtur Paszkiewicz 1974b42cb0e5SArtur Paszkiewicz SPDK_DEBUGLOG(bdev_raid, "slot: %u raid_ch: %p\n", idx, raid_ch); 1975b42cb0e5SArtur Paszkiewicz 1976b42cb0e5SArtur Paszkiewicz if (raid_ch->base_channel[idx] != NULL) { 1977b42cb0e5SArtur Paszkiewicz spdk_put_io_channel(raid_ch->base_channel[idx]); 1978b42cb0e5SArtur Paszkiewicz raid_ch->base_channel[idx] = NULL; 1979b42cb0e5SArtur Paszkiewicz } 1980b42cb0e5SArtur Paszkiewicz 1981aae5e04fSArtur Paszkiewicz if (raid_ch->process.ch_processed != NULL) { 1982aae5e04fSArtur Paszkiewicz raid_ch->process.ch_processed->base_channel[idx] = NULL; 1983aae5e04fSArtur Paszkiewicz } 1984aae5e04fSArtur Paszkiewicz 1985b42cb0e5SArtur Paszkiewicz spdk_for_each_channel_continue(i, 0); 1986b42cb0e5SArtur Paszkiewicz } 1987b42cb0e5SArtur Paszkiewicz 1988b42cb0e5SArtur Paszkiewicz static void 1989b42cb0e5SArtur Paszkiewicz raid_bdev_channels_remove_base_bdev_done(struct spdk_io_channel_iter *i, int status) 1990b42cb0e5SArtur Paszkiewicz { 1991b42cb0e5SArtur Paszkiewicz struct raid_base_bdev_info *base_info = spdk_io_channel_iter_get_ctx(i); 1992b42cb0e5SArtur Paszkiewicz struct raid_bdev *raid_bdev = base_info->raid_bdev; 1993b42cb0e5SArtur Paszkiewicz 19942dc74a00SArtur Paszkiewicz raid_bdev_free_base_bdev_resource(base_info); 19952dc74a00SArtur Paszkiewicz 1996b42cb0e5SArtur Paszkiewicz spdk_bdev_unquiesce(&raid_bdev->bdev, &g_raid_if, raid_bdev_remove_base_bdev_on_unquiesced, 1997b42cb0e5SArtur Paszkiewicz base_info); 1998b42cb0e5SArtur Paszkiewicz } 1999b42cb0e5SArtur Paszkiewicz 2000b42cb0e5SArtur Paszkiewicz static void 2001cb768e81SArtur Paszkiewicz raid_bdev_remove_base_bdev_cont(struct raid_base_bdev_info *base_info) 2002cb768e81SArtur Paszkiewicz { 2003cb768e81SArtur Paszkiewicz raid_bdev_deconfigure_base_bdev(base_info); 2004cb768e81SArtur Paszkiewicz 2005cb768e81SArtur Paszkiewicz spdk_for_each_channel(base_info->raid_bdev, raid_bdev_channel_remove_base_bdev, base_info, 2006cb768e81SArtur Paszkiewicz raid_bdev_channels_remove_base_bdev_done); 2007cb768e81SArtur Paszkiewicz } 2008cb768e81SArtur Paszkiewicz 2009cb768e81SArtur Paszkiewicz static void 2010cb768e81SArtur Paszkiewicz raid_bdev_remove_base_bdev_write_sb_cb(int status, struct raid_bdev *raid_bdev, void *ctx) 2011cb768e81SArtur Paszkiewicz { 2012cb768e81SArtur Paszkiewicz struct raid_base_bdev_info *base_info = ctx; 2013cb768e81SArtur Paszkiewicz 2014cb768e81SArtur Paszkiewicz if (status != 0) { 2015cb768e81SArtur Paszkiewicz SPDK_ERRLOG("Failed to write raid bdev '%s' superblock: %s\n", 2016cb768e81SArtur Paszkiewicz raid_bdev->bdev.name, spdk_strerror(-status)); 2017cb768e81SArtur Paszkiewicz raid_bdev_remove_base_bdev_done(base_info, status); 2018cb768e81SArtur Paszkiewicz return; 2019cb768e81SArtur Paszkiewicz } 2020cb768e81SArtur Paszkiewicz 2021cb768e81SArtur Paszkiewicz raid_bdev_remove_base_bdev_cont(base_info); 2022cb768e81SArtur Paszkiewicz } 2023cb768e81SArtur Paszkiewicz 2024cb768e81SArtur Paszkiewicz static void 2025b42cb0e5SArtur Paszkiewicz raid_bdev_remove_base_bdev_on_quiesced(void *ctx, int status) 2026b42cb0e5SArtur Paszkiewicz { 2027b42cb0e5SArtur Paszkiewicz struct raid_base_bdev_info *base_info = ctx; 2028b42cb0e5SArtur Paszkiewicz struct raid_bdev *raid_bdev = base_info->raid_bdev; 2029b42cb0e5SArtur Paszkiewicz 2030b42cb0e5SArtur Paszkiewicz if (status != 0) { 2031b42cb0e5SArtur Paszkiewicz SPDK_ERRLOG("Failed to quiesce raid bdev %s: %s\n", 2032b42cb0e5SArtur Paszkiewicz raid_bdev->bdev.name, spdk_strerror(-status)); 20334cc10656SArtur Paszkiewicz raid_bdev_remove_base_bdev_done(base_info, status); 2034b42cb0e5SArtur Paszkiewicz return; 2035b42cb0e5SArtur Paszkiewicz } 2036b42cb0e5SArtur Paszkiewicz 2037cb768e81SArtur Paszkiewicz if (raid_bdev->sb) { 2038cb768e81SArtur Paszkiewicz struct raid_bdev_superblock *sb = raid_bdev->sb; 2039cb768e81SArtur Paszkiewicz uint8_t slot = raid_bdev_base_bdev_slot(base_info); 2040cb768e81SArtur Paszkiewicz uint8_t i; 20416518a98dSArtur Paszkiewicz 2042cb768e81SArtur Paszkiewicz for (i = 0; i < sb->base_bdevs_size; i++) { 2043cb768e81SArtur Paszkiewicz struct raid_bdev_sb_base_bdev *sb_base_bdev = &sb->base_bdevs[i]; 2044cb768e81SArtur Paszkiewicz 2045cb768e81SArtur Paszkiewicz if (sb_base_bdev->state == RAID_SB_BASE_BDEV_CONFIGURED && 2046cb768e81SArtur Paszkiewicz sb_base_bdev->slot == slot) { 2047f1a03e33SArtur Paszkiewicz if (base_info->is_failed) { 2048cb768e81SArtur Paszkiewicz sb_base_bdev->state = RAID_SB_BASE_BDEV_FAILED; 2049f1a03e33SArtur Paszkiewicz } else { 2050f1a03e33SArtur Paszkiewicz sb_base_bdev->state = RAID_SB_BASE_BDEV_MISSING; 2051f1a03e33SArtur Paszkiewicz } 2052cb768e81SArtur Paszkiewicz 2053cb768e81SArtur Paszkiewicz raid_bdev_write_superblock(raid_bdev, raid_bdev_remove_base_bdev_write_sb_cb, base_info); 2054cb768e81SArtur Paszkiewicz return; 2055cb768e81SArtur Paszkiewicz } 2056cb768e81SArtur Paszkiewicz } 2057cb768e81SArtur Paszkiewicz } 2058cb768e81SArtur Paszkiewicz 2059cb768e81SArtur Paszkiewicz raid_bdev_remove_base_bdev_cont(base_info); 2060b42cb0e5SArtur Paszkiewicz } 2061b42cb0e5SArtur Paszkiewicz 20620ace905fSArtur Paszkiewicz static int 2063d6fa87aeSArtur Paszkiewicz raid_bdev_remove_base_bdev_quiesce(struct raid_base_bdev_info *base_info) 2064d6fa87aeSArtur Paszkiewicz { 2065d6fa87aeSArtur Paszkiewicz assert(spdk_get_thread() == spdk_thread_get_app_thread()); 2066d6fa87aeSArtur Paszkiewicz 2067d6fa87aeSArtur Paszkiewicz return spdk_bdev_quiesce(&base_info->raid_bdev->bdev, &g_raid_if, 2068d6fa87aeSArtur Paszkiewicz raid_bdev_remove_base_bdev_on_quiesced, base_info); 2069d6fa87aeSArtur Paszkiewicz } 2070d6fa87aeSArtur Paszkiewicz 2071d6fa87aeSArtur Paszkiewicz struct raid_bdev_process_base_bdev_remove_ctx { 2072d6fa87aeSArtur Paszkiewicz struct raid_bdev_process *process; 2073d6fa87aeSArtur Paszkiewicz struct raid_base_bdev_info *base_info; 2074d6fa87aeSArtur Paszkiewicz uint8_t num_base_bdevs_operational; 2075d6fa87aeSArtur Paszkiewicz }; 2076d6fa87aeSArtur Paszkiewicz 2077d6fa87aeSArtur Paszkiewicz static void 2078d6fa87aeSArtur Paszkiewicz _raid_bdev_process_base_bdev_remove_cont(void *ctx) 2079d6fa87aeSArtur Paszkiewicz { 2080d6fa87aeSArtur Paszkiewicz struct raid_base_bdev_info *base_info = ctx; 2081d6fa87aeSArtur Paszkiewicz int ret; 2082d6fa87aeSArtur Paszkiewicz 2083d6fa87aeSArtur Paszkiewicz ret = raid_bdev_remove_base_bdev_quiesce(base_info); 2084d6fa87aeSArtur Paszkiewicz if (ret != 0) { 2085d6fa87aeSArtur Paszkiewicz raid_bdev_remove_base_bdev_done(base_info, ret); 2086d6fa87aeSArtur Paszkiewicz } 2087d6fa87aeSArtur Paszkiewicz } 2088d6fa87aeSArtur Paszkiewicz 2089d6fa87aeSArtur Paszkiewicz static void 2090d6fa87aeSArtur Paszkiewicz raid_bdev_process_base_bdev_remove_cont(void *_ctx) 2091d6fa87aeSArtur Paszkiewicz { 2092d6fa87aeSArtur Paszkiewicz struct raid_bdev_process_base_bdev_remove_ctx *ctx = _ctx; 2093d6fa87aeSArtur Paszkiewicz struct raid_base_bdev_info *base_info = ctx->base_info; 2094d6fa87aeSArtur Paszkiewicz 2095d6fa87aeSArtur Paszkiewicz free(ctx); 2096d6fa87aeSArtur Paszkiewicz 2097d6fa87aeSArtur Paszkiewicz spdk_thread_send_msg(spdk_thread_get_app_thread(), _raid_bdev_process_base_bdev_remove_cont, 2098d6fa87aeSArtur Paszkiewicz base_info); 2099d6fa87aeSArtur Paszkiewicz } 2100d6fa87aeSArtur Paszkiewicz 2101d6fa87aeSArtur Paszkiewicz static void 2102d6fa87aeSArtur Paszkiewicz _raid_bdev_process_base_bdev_remove(void *_ctx) 2103d6fa87aeSArtur Paszkiewicz { 2104d6fa87aeSArtur Paszkiewicz struct raid_bdev_process_base_bdev_remove_ctx *ctx = _ctx; 2105d6fa87aeSArtur Paszkiewicz struct raid_bdev_process *process = ctx->process; 2106d6fa87aeSArtur Paszkiewicz int ret; 2107d6fa87aeSArtur Paszkiewicz 2108d6fa87aeSArtur Paszkiewicz if (ctx->base_info != process->target && 2109d6fa87aeSArtur Paszkiewicz ctx->num_base_bdevs_operational > process->raid_bdev->min_base_bdevs_operational) { 2110d6fa87aeSArtur Paszkiewicz /* process doesn't need to be stopped */ 2111d6fa87aeSArtur Paszkiewicz raid_bdev_process_base_bdev_remove_cont(ctx); 2112d6fa87aeSArtur Paszkiewicz return; 2113d6fa87aeSArtur Paszkiewicz } 2114d6fa87aeSArtur Paszkiewicz 2115d6fa87aeSArtur Paszkiewicz assert(process->state > RAID_PROCESS_STATE_INIT && 2116d6fa87aeSArtur Paszkiewicz process->state < RAID_PROCESS_STATE_STOPPED); 2117d6fa87aeSArtur Paszkiewicz 2118d6fa87aeSArtur Paszkiewicz ret = raid_bdev_process_add_finish_action(process, raid_bdev_process_base_bdev_remove_cont, ctx); 2119d6fa87aeSArtur Paszkiewicz if (ret != 0) { 2120d6fa87aeSArtur Paszkiewicz raid_bdev_remove_base_bdev_done(ctx->base_info, ret); 2121d6fa87aeSArtur Paszkiewicz free(ctx); 2122d6fa87aeSArtur Paszkiewicz return; 2123d6fa87aeSArtur Paszkiewicz } 2124d6fa87aeSArtur Paszkiewicz 2125d6fa87aeSArtur Paszkiewicz process->state = RAID_PROCESS_STATE_STOPPING; 2126d6fa87aeSArtur Paszkiewicz 2127d6fa87aeSArtur Paszkiewicz if (process->status == 0) { 2128d6fa87aeSArtur Paszkiewicz process->status = -ENODEV; 2129d6fa87aeSArtur Paszkiewicz } 2130d6fa87aeSArtur Paszkiewicz } 2131d6fa87aeSArtur Paszkiewicz 2132d6fa87aeSArtur Paszkiewicz static int 2133d6fa87aeSArtur Paszkiewicz raid_bdev_process_base_bdev_remove(struct raid_bdev_process *process, 2134d6fa87aeSArtur Paszkiewicz struct raid_base_bdev_info *base_info) 2135d6fa87aeSArtur Paszkiewicz { 2136d6fa87aeSArtur Paszkiewicz struct raid_bdev_process_base_bdev_remove_ctx *ctx; 2137d6fa87aeSArtur Paszkiewicz 2138d6fa87aeSArtur Paszkiewicz assert(spdk_get_thread() == spdk_thread_get_app_thread()); 2139d6fa87aeSArtur Paszkiewicz 2140d6fa87aeSArtur Paszkiewicz ctx = calloc(1, sizeof(*ctx)); 2141d6fa87aeSArtur Paszkiewicz if (ctx == NULL) { 2142d6fa87aeSArtur Paszkiewicz return -ENOMEM; 2143d6fa87aeSArtur Paszkiewicz } 2144d6fa87aeSArtur Paszkiewicz 2145d6fa87aeSArtur Paszkiewicz /* 2146d6fa87aeSArtur Paszkiewicz * We have to send the process and num_base_bdevs_operational in the message ctx 2147d6fa87aeSArtur Paszkiewicz * because the process thread should not access raid_bdev's properties. Particularly, 2148d6fa87aeSArtur Paszkiewicz * raid_bdev->process may be cleared by the time the message is handled, but ctx->process 2149d6fa87aeSArtur Paszkiewicz * will still be valid until the process is fully stopped. 2150d6fa87aeSArtur Paszkiewicz */ 2151d6fa87aeSArtur Paszkiewicz ctx->base_info = base_info; 2152d6fa87aeSArtur Paszkiewicz ctx->process = process; 21532ea7b741SArtur Paszkiewicz /* 21542ea7b741SArtur Paszkiewicz * raid_bdev->num_base_bdevs_operational can't be used here because it is decremented 21552ea7b741SArtur Paszkiewicz * after the removal and more than one base bdev may be removed at the same time 21562ea7b741SArtur Paszkiewicz */ 21572ea7b741SArtur Paszkiewicz RAID_FOR_EACH_BASE_BDEV(process->raid_bdev, base_info) { 21586518a98dSArtur Paszkiewicz if (base_info->is_configured && !base_info->remove_scheduled) { 21592ea7b741SArtur Paszkiewicz ctx->num_base_bdevs_operational++; 21602ea7b741SArtur Paszkiewicz } 21612ea7b741SArtur Paszkiewicz } 2162d6fa87aeSArtur Paszkiewicz 2163d6fa87aeSArtur Paszkiewicz spdk_thread_send_msg(process->thread, _raid_bdev_process_base_bdev_remove, ctx); 2164d6fa87aeSArtur Paszkiewicz 2165d6fa87aeSArtur Paszkiewicz return 0; 2166d6fa87aeSArtur Paszkiewicz } 2167d6fa87aeSArtur Paszkiewicz 2168d6fa87aeSArtur Paszkiewicz static int 21690ace905fSArtur Paszkiewicz _raid_bdev_remove_base_bdev(struct raid_base_bdev_info *base_info, 2170887b8ec4SArtur Paszkiewicz raid_base_bdev_cb cb_fn, void *cb_ctx) 217107fe6a43SSeth Howell { 21720ace905fSArtur Paszkiewicz struct raid_bdev *raid_bdev = base_info->raid_bdev; 2173d6fa87aeSArtur Paszkiewicz int ret = 0; 217407fe6a43SSeth Howell 21750ace905fSArtur Paszkiewicz SPDK_DEBUGLOG(bdev_raid, "%s\n", base_info->name); 217607fe6a43SSeth Howell 21774dd2a0d3SArtur Paszkiewicz assert(spdk_get_thread() == spdk_thread_get_app_thread()); 21784dd2a0d3SArtur Paszkiewicz 2179b3750343SArtur Paszkiewicz if (base_info->remove_scheduled || !base_info->is_configured) { 2180d6fa87aeSArtur Paszkiewicz return -ENODEV; 2181b42cb0e5SArtur Paszkiewicz } 2182b42cb0e5SArtur Paszkiewicz 2183a193dcb8SArtur Paszkiewicz assert(base_info->desc); 2184a193dcb8SArtur Paszkiewicz base_info->remove_scheduled = true; 218507fe6a43SSeth Howell 21864ad1ac90SArtur Paszkiewicz if (raid_bdev->state != RAID_BDEV_STATE_ONLINE) { 218707fe6a43SSeth Howell /* 218807fe6a43SSeth Howell * As raid bdev is not registered yet or already unregistered, 218907fe6a43SSeth Howell * so cleanup should be done here itself. 2190255d0786SArtur Paszkiewicz * 2191255d0786SArtur Paszkiewicz * Removing a base bdev at this stage does not change the number of operational 2192255d0786SArtur Paszkiewicz * base bdevs, only the number of discovered base bdevs. 219307fe6a43SSeth Howell */ 219426861b70SArtur Paszkiewicz raid_bdev_free_base_bdev_resource(base_info); 2195bf3ddff0SArtur Paszkiewicz base_info->remove_scheduled = false; 2196bad11eeaSArtur Paszkiewicz if (raid_bdev->num_base_bdevs_discovered == 0 && 2197bad11eeaSArtur Paszkiewicz raid_bdev->state == RAID_BDEV_STATE_OFFLINE) { 219807fe6a43SSeth Howell /* There is no base bdev for this raid, so free the raid device. */ 219995a04949SArtur Paszkiewicz raid_bdev_cleanup_and_free(raid_bdev); 2200b42cb0e5SArtur Paszkiewicz } 22019d6e1f5bSYankun Li if (cb_fn != NULL) { 22029d6e1f5bSYankun Li cb_fn(cb_ctx, 0); 22039d6e1f5bSYankun Li } 22042ea7b741SArtur Paszkiewicz } else if (raid_bdev->min_base_bdevs_operational == raid_bdev->num_base_bdevs) { 22052ea7b741SArtur Paszkiewicz /* This raid bdev does not tolerate removing a base bdev. */ 22062ea7b741SArtur Paszkiewicz raid_bdev->num_base_bdevs_operational--; 220723850b03SKrzysztof Smolinski raid_bdev_deconfigure(raid_bdev, cb_fn, cb_ctx); 22082ea7b741SArtur Paszkiewicz } else { 22092ea7b741SArtur Paszkiewicz base_info->remove_cb = cb_fn; 22102ea7b741SArtur Paszkiewicz base_info->remove_cb_ctx = cb_ctx; 22112ea7b741SArtur Paszkiewicz 22122ea7b741SArtur Paszkiewicz if (raid_bdev->process != NULL) { 2213d6fa87aeSArtur Paszkiewicz ret = raid_bdev_process_base_bdev_remove(raid_bdev->process, base_info); 2214b42cb0e5SArtur Paszkiewicz } else { 2215d6fa87aeSArtur Paszkiewicz ret = raid_bdev_remove_base_bdev_quiesce(base_info); 2216d6fa87aeSArtur Paszkiewicz } 2217b42cb0e5SArtur Paszkiewicz 2218b42cb0e5SArtur Paszkiewicz if (ret != 0) { 2219b42cb0e5SArtur Paszkiewicz base_info->remove_scheduled = false; 222007fe6a43SSeth Howell } 22212ea7b741SArtur Paszkiewicz } 22222ea7b741SArtur Paszkiewicz 2223d6fa87aeSArtur Paszkiewicz return ret; 222407fe6a43SSeth Howell } 222507fe6a43SSeth Howell 222607fe6a43SSeth Howell /* 222707fe6a43SSeth Howell * brief: 22280ace905fSArtur Paszkiewicz * raid_bdev_remove_base_bdev function is called by below layers when base_bdev 22290ace905fSArtur Paszkiewicz * is removed. This function checks if this base bdev is part of any raid bdev 22300ace905fSArtur Paszkiewicz * or not. If yes, it takes necessary action on that particular raid bdev. 22310ace905fSArtur Paszkiewicz * params: 22320ace905fSArtur Paszkiewicz * base_bdev - pointer to base bdev which got removed 22330ace905fSArtur Paszkiewicz * cb_fn - callback function 22340ace905fSArtur Paszkiewicz * cb_arg - argument to callback function 22350ace905fSArtur Paszkiewicz * returns: 22360ace905fSArtur Paszkiewicz * 0 - success 22370ace905fSArtur Paszkiewicz * non zero - failure 22380ace905fSArtur Paszkiewicz */ 22390ace905fSArtur Paszkiewicz int 2240887b8ec4SArtur Paszkiewicz raid_bdev_remove_base_bdev(struct spdk_bdev *base_bdev, raid_base_bdev_cb cb_fn, void *cb_ctx) 22410ace905fSArtur Paszkiewicz { 22420ace905fSArtur Paszkiewicz struct raid_base_bdev_info *base_info; 22430ace905fSArtur Paszkiewicz 22440ace905fSArtur Paszkiewicz /* Find the raid_bdev which has claimed this base_bdev */ 22450ace905fSArtur Paszkiewicz base_info = raid_bdev_find_base_info_by_bdev(base_bdev); 22460ace905fSArtur Paszkiewicz if (!base_info) { 22470ace905fSArtur Paszkiewicz SPDK_ERRLOG("bdev to remove '%s' not found\n", base_bdev->name); 22480ace905fSArtur Paszkiewicz return -ENODEV; 22490ace905fSArtur Paszkiewicz } 22500ace905fSArtur Paszkiewicz 22510ace905fSArtur Paszkiewicz return _raid_bdev_remove_base_bdev(base_info, cb_fn, cb_ctx); 22520ace905fSArtur Paszkiewicz } 22530ace905fSArtur Paszkiewicz 2254ceb2ad0cSArtur Paszkiewicz static void 2255f1a03e33SArtur Paszkiewicz raid_bdev_fail_base_remove_cb(void *ctx, int status) 2256f1a03e33SArtur Paszkiewicz { 2257f1a03e33SArtur Paszkiewicz struct raid_base_bdev_info *base_info = ctx; 2258f1a03e33SArtur Paszkiewicz 2259f1a03e33SArtur Paszkiewicz if (status != 0) { 2260f1a03e33SArtur Paszkiewicz SPDK_WARNLOG("Failed to remove base bdev %s\n", base_info->name); 2261f1a03e33SArtur Paszkiewicz base_info->is_failed = false; 2262f1a03e33SArtur Paszkiewicz } 2263f1a03e33SArtur Paszkiewicz } 2264f1a03e33SArtur Paszkiewicz 2265f1a03e33SArtur Paszkiewicz static void 2266f1a03e33SArtur Paszkiewicz _raid_bdev_fail_base_bdev(void *ctx) 2267f1a03e33SArtur Paszkiewicz { 2268f1a03e33SArtur Paszkiewicz struct raid_base_bdev_info *base_info = ctx; 2269f1a03e33SArtur Paszkiewicz int rc; 2270f1a03e33SArtur Paszkiewicz 2271f1a03e33SArtur Paszkiewicz if (base_info->is_failed) { 2272f1a03e33SArtur Paszkiewicz return; 2273f1a03e33SArtur Paszkiewicz } 2274f1a03e33SArtur Paszkiewicz base_info->is_failed = true; 2275f1a03e33SArtur Paszkiewicz 2276f1a03e33SArtur Paszkiewicz SPDK_NOTICELOG("Failing base bdev in slot %d ('%s') of raid bdev '%s'\n", 2277f1a03e33SArtur Paszkiewicz raid_bdev_base_bdev_slot(base_info), base_info->name, base_info->raid_bdev->bdev.name); 2278f1a03e33SArtur Paszkiewicz 2279f1a03e33SArtur Paszkiewicz rc = _raid_bdev_remove_base_bdev(base_info, raid_bdev_fail_base_remove_cb, base_info); 2280f1a03e33SArtur Paszkiewicz if (rc != 0) { 2281f1a03e33SArtur Paszkiewicz raid_bdev_fail_base_remove_cb(base_info, rc); 2282f1a03e33SArtur Paszkiewicz } 2283f1a03e33SArtur Paszkiewicz } 2284f1a03e33SArtur Paszkiewicz 2285f1a03e33SArtur Paszkiewicz void 2286f1a03e33SArtur Paszkiewicz raid_bdev_fail_base_bdev(struct raid_base_bdev_info *base_info) 2287f1a03e33SArtur Paszkiewicz { 2288f1a03e33SArtur Paszkiewicz spdk_thread_exec_msg(spdk_thread_get_app_thread(), _raid_bdev_fail_base_bdev, base_info); 2289f1a03e33SArtur Paszkiewicz } 2290f1a03e33SArtur Paszkiewicz 2291f1a03e33SArtur Paszkiewicz static void 2292ceb2ad0cSArtur Paszkiewicz raid_bdev_resize_write_sb_cb(int status, struct raid_bdev *raid_bdev, void *ctx) 2293ceb2ad0cSArtur Paszkiewicz { 2294ceb2ad0cSArtur Paszkiewicz if (status != 0) { 2295ceb2ad0cSArtur Paszkiewicz SPDK_ERRLOG("Failed to write raid bdev '%s' superblock after resizing the bdev: %s\n", 2296ceb2ad0cSArtur Paszkiewicz raid_bdev->bdev.name, spdk_strerror(-status)); 2297ceb2ad0cSArtur Paszkiewicz } 2298ceb2ad0cSArtur Paszkiewicz } 2299ceb2ad0cSArtur Paszkiewicz 23000ace905fSArtur Paszkiewicz /* 23010ace905fSArtur Paszkiewicz * brief: 2302c9224e26SShuhei Matsumoto * raid_bdev_resize_base_bdev function is called by below layers when base_bdev 2303c9224e26SShuhei Matsumoto * is resized. This function checks if the smallest size of the base_bdevs is changed. 2304c9224e26SShuhei Matsumoto * If yes, call module handler to resize the raid_bdev if implemented. 2305c9224e26SShuhei Matsumoto * params: 2306c9224e26SShuhei Matsumoto * base_bdev - pointer to base bdev which got resized. 2307c9224e26SShuhei Matsumoto * returns: 2308c9224e26SShuhei Matsumoto * none 2309c9224e26SShuhei Matsumoto */ 2310c9224e26SShuhei Matsumoto static void 2311c9224e26SShuhei Matsumoto raid_bdev_resize_base_bdev(struct spdk_bdev *base_bdev) 2312c9224e26SShuhei Matsumoto { 231326861b70SArtur Paszkiewicz struct raid_bdev *raid_bdev; 2314c9224e26SShuhei Matsumoto struct raid_base_bdev_info *base_info; 2315ba09b57fSArtur Paszkiewicz uint64_t blockcnt_old; 2316c9224e26SShuhei Matsumoto 2317c9224e26SShuhei Matsumoto SPDK_DEBUGLOG(bdev_raid, "raid_bdev_resize_base_bdev\n"); 2318c9224e26SShuhei Matsumoto 231926861b70SArtur Paszkiewicz base_info = raid_bdev_find_base_info_by_bdev(base_bdev); 232026861b70SArtur Paszkiewicz 2321c9224e26SShuhei Matsumoto /* Find the raid_bdev which has claimed this base_bdev */ 232226861b70SArtur Paszkiewicz if (!base_info) { 2323c9224e26SShuhei Matsumoto SPDK_ERRLOG("raid_bdev whose base_bdev '%s' not found\n", base_bdev->name); 2324c9224e26SShuhei Matsumoto return; 2325c9224e26SShuhei Matsumoto } 232626861b70SArtur Paszkiewicz raid_bdev = base_info->raid_bdev; 2327c9224e26SShuhei Matsumoto 2328c9224e26SShuhei Matsumoto assert(spdk_get_thread() == spdk_thread_get_app_thread()); 2329c9224e26SShuhei Matsumoto 2330c9224e26SShuhei Matsumoto SPDK_NOTICELOG("base_bdev '%s' was resized: old size %" PRIu64 ", new size %" PRIu64 "\n", 2331c9224e26SShuhei Matsumoto base_bdev->name, base_info->blockcnt, base_bdev->blockcnt); 2332c9224e26SShuhei Matsumoto 23332e6e9553SArtur Paszkiewicz base_info->blockcnt = base_bdev->blockcnt; 23342e6e9553SArtur Paszkiewicz 2335ceb2ad0cSArtur Paszkiewicz if (!raid_bdev->module->resize) { 2336ceb2ad0cSArtur Paszkiewicz return; 2337ceb2ad0cSArtur Paszkiewicz } 2338ceb2ad0cSArtur Paszkiewicz 2339ba09b57fSArtur Paszkiewicz blockcnt_old = raid_bdev->bdev.blockcnt; 2340ceb2ad0cSArtur Paszkiewicz if (raid_bdev->module->resize(raid_bdev) == false) { 2341ceb2ad0cSArtur Paszkiewicz return; 2342ceb2ad0cSArtur Paszkiewicz } 2343ceb2ad0cSArtur Paszkiewicz 2344ba09b57fSArtur Paszkiewicz SPDK_NOTICELOG("raid bdev '%s': block count was changed from %" PRIu64 " to %" PRIu64 "\n", 2345ba09b57fSArtur Paszkiewicz raid_bdev->bdev.name, blockcnt_old, raid_bdev->bdev.blockcnt); 2346ba09b57fSArtur Paszkiewicz 2347ceb2ad0cSArtur Paszkiewicz if (raid_bdev->superblock_enabled) { 2348ceb2ad0cSArtur Paszkiewicz struct raid_bdev_superblock *sb = raid_bdev->sb; 2349ceb2ad0cSArtur Paszkiewicz uint8_t i; 2350ceb2ad0cSArtur Paszkiewicz 2351ceb2ad0cSArtur Paszkiewicz for (i = 0; i < sb->base_bdevs_size; i++) { 2352ceb2ad0cSArtur Paszkiewicz struct raid_bdev_sb_base_bdev *sb_base_bdev = &sb->base_bdevs[i]; 2353ceb2ad0cSArtur Paszkiewicz 2354d005e023SArtur Paszkiewicz if (sb_base_bdev->slot < raid_bdev->num_base_bdevs) { 2355ceb2ad0cSArtur Paszkiewicz base_info = &raid_bdev->base_bdev_info[sb_base_bdev->slot]; 2356ceb2ad0cSArtur Paszkiewicz sb_base_bdev->data_size = base_info->data_size; 2357ceb2ad0cSArtur Paszkiewicz } 2358ceb2ad0cSArtur Paszkiewicz } 2359ceb2ad0cSArtur Paszkiewicz sb->raid_size = raid_bdev->bdev.blockcnt; 2360ceb2ad0cSArtur Paszkiewicz raid_bdev_write_superblock(raid_bdev, raid_bdev_resize_write_sb_cb, NULL); 2361c9224e26SShuhei Matsumoto } 2362c9224e26SShuhei Matsumoto } 2363c9224e26SShuhei Matsumoto 2364c9224e26SShuhei Matsumoto /* 2365c9224e26SShuhei Matsumoto * brief: 2366d8a18924SShuhei Matsumoto * raid_bdev_event_base_bdev function is called by below layers when base_bdev 2367d8a18924SShuhei Matsumoto * triggers asynchronous event. 2368d8a18924SShuhei Matsumoto * params: 2369d8a18924SShuhei Matsumoto * type - event details. 2370d8a18924SShuhei Matsumoto * bdev - bdev that triggered event. 2371d8a18924SShuhei Matsumoto * event_ctx - context for event. 2372d8a18924SShuhei Matsumoto * returns: 2373d8a18924SShuhei Matsumoto * none 2374d8a18924SShuhei Matsumoto */ 2375d8a18924SShuhei Matsumoto static void 2376d8a18924SShuhei Matsumoto raid_bdev_event_base_bdev(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, 2377d8a18924SShuhei Matsumoto void *event_ctx) 2378d8a18924SShuhei Matsumoto { 2379b42cb0e5SArtur Paszkiewicz int rc; 2380b42cb0e5SArtur Paszkiewicz 2381d8a18924SShuhei Matsumoto switch (type) { 2382d8a18924SShuhei Matsumoto case SPDK_BDEV_EVENT_REMOVE: 238323850b03SKrzysztof Smolinski rc = raid_bdev_remove_base_bdev(bdev, NULL, NULL); 2384b42cb0e5SArtur Paszkiewicz if (rc != 0) { 2385b42cb0e5SArtur Paszkiewicz SPDK_ERRLOG("Failed to remove base bdev %s: %s\n", 2386b42cb0e5SArtur Paszkiewicz spdk_bdev_get_name(bdev), spdk_strerror(-rc)); 2387b42cb0e5SArtur Paszkiewicz } 2388d8a18924SShuhei Matsumoto break; 2389c9224e26SShuhei Matsumoto case SPDK_BDEV_EVENT_RESIZE: 2390c9224e26SShuhei Matsumoto raid_bdev_resize_base_bdev(bdev); 2391c9224e26SShuhei Matsumoto break; 2392d8a18924SShuhei Matsumoto default: 2393d8a18924SShuhei Matsumoto SPDK_NOTICELOG("Unsupported bdev event: type %d\n", type); 2394d8a18924SShuhei Matsumoto break; 2395d8a18924SShuhei Matsumoto } 2396d8a18924SShuhei Matsumoto } 2397d8a18924SShuhei Matsumoto 2398d8a18924SShuhei Matsumoto /* 2399d8a18924SShuhei Matsumoto * brief: 2400dccdd1e5SArtur Paszkiewicz * Deletes the specified raid bdev 240107fe6a43SSeth Howell * params: 2402dccdd1e5SArtur Paszkiewicz * raid_bdev - pointer to raid bdev 240307fe6a43SSeth Howell * cb_fn - callback function 2404dccdd1e5SArtur Paszkiewicz * cb_arg - argument to callback function 240507fe6a43SSeth Howell */ 240607fe6a43SSeth Howell void 2407dccdd1e5SArtur Paszkiewicz raid_bdev_delete(struct raid_bdev *raid_bdev, raid_bdev_destruct_cb cb_fn, void *cb_arg) 240807fe6a43SSeth Howell { 2409a193dcb8SArtur Paszkiewicz struct raid_base_bdev_info *base_info; 241007fe6a43SSeth Howell 2411dccdd1e5SArtur Paszkiewicz SPDK_DEBUGLOG(bdev_raid, "delete raid bdev: %s\n", raid_bdev->bdev.name); 241207fe6a43SSeth Howell 241307fe6a43SSeth Howell if (raid_bdev->destroy_started) { 24142172c432STomasz Zawadzki SPDK_DEBUGLOG(bdev_raid, "destroying raid bdev %s is already started\n", 2415dccdd1e5SArtur Paszkiewicz raid_bdev->bdev.name); 241607fe6a43SSeth Howell if (cb_fn) { 241707fe6a43SSeth Howell cb_fn(cb_arg, -EALREADY); 241807fe6a43SSeth Howell } 241907fe6a43SSeth Howell return; 242007fe6a43SSeth Howell } 242107fe6a43SSeth Howell 242207fe6a43SSeth Howell raid_bdev->destroy_started = true; 242307fe6a43SSeth Howell 2424a193dcb8SArtur Paszkiewicz RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) { 2425a193dcb8SArtur Paszkiewicz base_info->remove_scheduled = true; 242607fe6a43SSeth Howell 24274ad1ac90SArtur Paszkiewicz if (raid_bdev->state != RAID_BDEV_STATE_ONLINE) { 242807fe6a43SSeth Howell /* 242907fe6a43SSeth Howell * As raid bdev is not registered yet or already unregistered, 243007fe6a43SSeth Howell * so cleanup should be done here itself. 243107fe6a43SSeth Howell */ 243226861b70SArtur Paszkiewicz raid_bdev_free_base_bdev_resource(base_info); 2433df1e07e9SGangCao } 2434df1e07e9SGangCao } 2435df1e07e9SGangCao 243607fe6a43SSeth Howell if (raid_bdev->num_base_bdevs_discovered == 0) { 243707fe6a43SSeth Howell /* There is no base bdev for this raid, so free the raid device. */ 243895a04949SArtur Paszkiewicz raid_bdev_cleanup_and_free(raid_bdev); 243907fe6a43SSeth Howell if (cb_fn) { 244007fe6a43SSeth Howell cb_fn(cb_arg, 0); 244107fe6a43SSeth Howell } 2442df1e07e9SGangCao } else { 244307fe6a43SSeth Howell raid_bdev_deconfigure(raid_bdev, cb_fn, cb_arg); 244407fe6a43SSeth Howell } 2445df1e07e9SGangCao } 244607fe6a43SSeth Howell 24479222ff97SArtur Paszkiewicz static void 244850d58ff3SArtur Paszkiewicz raid_bdev_process_finish_write_sb_cb(int status, struct raid_bdev *raid_bdev, void *ctx) 244950d58ff3SArtur Paszkiewicz { 245050d58ff3SArtur Paszkiewicz if (status != 0) { 245150d58ff3SArtur Paszkiewicz SPDK_ERRLOG("Failed to write raid bdev '%s' superblock after background process finished: %s\n", 245250d58ff3SArtur Paszkiewicz raid_bdev->bdev.name, spdk_strerror(-status)); 245350d58ff3SArtur Paszkiewicz } 245450d58ff3SArtur Paszkiewicz } 245550d58ff3SArtur Paszkiewicz 245650d58ff3SArtur Paszkiewicz static void 245750d58ff3SArtur Paszkiewicz raid_bdev_process_finish_write_sb(void *ctx) 245850d58ff3SArtur Paszkiewicz { 245950d58ff3SArtur Paszkiewicz struct raid_bdev *raid_bdev = ctx; 246050d58ff3SArtur Paszkiewicz struct raid_bdev_superblock *sb = raid_bdev->sb; 246150d58ff3SArtur Paszkiewicz struct raid_bdev_sb_base_bdev *sb_base_bdev; 246250d58ff3SArtur Paszkiewicz struct raid_base_bdev_info *base_info; 246350d58ff3SArtur Paszkiewicz uint8_t i; 246450d58ff3SArtur Paszkiewicz 246550d58ff3SArtur Paszkiewicz for (i = 0; i < sb->base_bdevs_size; i++) { 246650d58ff3SArtur Paszkiewicz sb_base_bdev = &sb->base_bdevs[i]; 246750d58ff3SArtur Paszkiewicz 246850d58ff3SArtur Paszkiewicz if (sb_base_bdev->state != RAID_SB_BASE_BDEV_CONFIGURED && 246950d58ff3SArtur Paszkiewicz sb_base_bdev->slot < raid_bdev->num_base_bdevs) { 247050d58ff3SArtur Paszkiewicz base_info = &raid_bdev->base_bdev_info[sb_base_bdev->slot]; 247150d58ff3SArtur Paszkiewicz if (base_info->is_configured) { 247250d58ff3SArtur Paszkiewicz sb_base_bdev->state = RAID_SB_BASE_BDEV_CONFIGURED; 24733cd7b237SSebastian Brzezinka sb_base_bdev->data_offset = base_info->data_offset; 247450d58ff3SArtur Paszkiewicz spdk_uuid_copy(&sb_base_bdev->uuid, &base_info->uuid); 247550d58ff3SArtur Paszkiewicz } 247650d58ff3SArtur Paszkiewicz } 247750d58ff3SArtur Paszkiewicz } 247850d58ff3SArtur Paszkiewicz 247950d58ff3SArtur Paszkiewicz raid_bdev_write_superblock(raid_bdev, raid_bdev_process_finish_write_sb_cb, NULL); 248050d58ff3SArtur Paszkiewicz } 248150d58ff3SArtur Paszkiewicz 248250d58ff3SArtur Paszkiewicz static void raid_bdev_process_free(struct raid_bdev_process *process); 248350d58ff3SArtur Paszkiewicz 248450d58ff3SArtur Paszkiewicz static void 248550d58ff3SArtur Paszkiewicz _raid_bdev_process_finish_done(void *ctx) 248650d58ff3SArtur Paszkiewicz { 248750d58ff3SArtur Paszkiewicz struct raid_bdev_process *process = ctx; 24889d2b7b41SArtur Paszkiewicz struct raid_process_finish_action *finish_action; 24899d2b7b41SArtur Paszkiewicz 24909d2b7b41SArtur Paszkiewicz while ((finish_action = TAILQ_FIRST(&process->finish_actions)) != NULL) { 24919d2b7b41SArtur Paszkiewicz TAILQ_REMOVE(&process->finish_actions, finish_action, link); 24929d2b7b41SArtur Paszkiewicz finish_action->cb(finish_action->cb_ctx); 24939d2b7b41SArtur Paszkiewicz free(finish_action); 24949d2b7b41SArtur Paszkiewicz } 249550d58ff3SArtur Paszkiewicz 249689fd1730Sxupeng9 spdk_poller_unregister(&process->qos.process_continue_poller); 249789fd1730Sxupeng9 249850d58ff3SArtur Paszkiewicz raid_bdev_process_free(process); 249950d58ff3SArtur Paszkiewicz 250050d58ff3SArtur Paszkiewicz spdk_thread_exit(spdk_get_thread()); 250150d58ff3SArtur Paszkiewicz } 250250d58ff3SArtur Paszkiewicz 250350d58ff3SArtur Paszkiewicz static void 250450d58ff3SArtur Paszkiewicz raid_bdev_process_finish_target_removed(void *ctx, int status) 250550d58ff3SArtur Paszkiewicz { 250650d58ff3SArtur Paszkiewicz struct raid_bdev_process *process = ctx; 250750d58ff3SArtur Paszkiewicz 250850d58ff3SArtur Paszkiewicz if (status != 0) { 250950d58ff3SArtur Paszkiewicz SPDK_ERRLOG("Failed to remove target bdev: %s\n", spdk_strerror(-status)); 251050d58ff3SArtur Paszkiewicz } 251150d58ff3SArtur Paszkiewicz 251250d58ff3SArtur Paszkiewicz spdk_thread_send_msg(process->thread, _raid_bdev_process_finish_done, process); 251350d58ff3SArtur Paszkiewicz } 251450d58ff3SArtur Paszkiewicz 251550d58ff3SArtur Paszkiewicz static void 251650d58ff3SArtur Paszkiewicz raid_bdev_process_finish_unquiesced(void *ctx, int status) 251750d58ff3SArtur Paszkiewicz { 251850d58ff3SArtur Paszkiewicz struct raid_bdev_process *process = ctx; 251950d58ff3SArtur Paszkiewicz 252050d58ff3SArtur Paszkiewicz if (status != 0) { 252150d58ff3SArtur Paszkiewicz SPDK_ERRLOG("Failed to unquiesce bdev: %s\n", spdk_strerror(-status)); 252250d58ff3SArtur Paszkiewicz } 252350d58ff3SArtur Paszkiewicz 252450d58ff3SArtur Paszkiewicz if (process->status != 0) { 2525b3750343SArtur Paszkiewicz status = _raid_bdev_remove_base_bdev(process->target, raid_bdev_process_finish_target_removed, 2526b3750343SArtur Paszkiewicz process); 2527b3750343SArtur Paszkiewicz if (status != 0) { 2528b3750343SArtur Paszkiewicz raid_bdev_process_finish_target_removed(process, status); 252950d58ff3SArtur Paszkiewicz } 2530b3750343SArtur Paszkiewicz return; 253150d58ff3SArtur Paszkiewicz } 253250d58ff3SArtur Paszkiewicz 253350d58ff3SArtur Paszkiewicz spdk_thread_send_msg(process->thread, _raid_bdev_process_finish_done, process); 253450d58ff3SArtur Paszkiewicz } 253550d58ff3SArtur Paszkiewicz 253650d58ff3SArtur Paszkiewicz static void 253750d58ff3SArtur Paszkiewicz raid_bdev_process_finish_unquiesce(void *ctx) 253850d58ff3SArtur Paszkiewicz { 253950d58ff3SArtur Paszkiewicz struct raid_bdev_process *process = ctx; 254050d58ff3SArtur Paszkiewicz int rc; 254150d58ff3SArtur Paszkiewicz 254250d58ff3SArtur Paszkiewicz rc = spdk_bdev_unquiesce(&process->raid_bdev->bdev, &g_raid_if, 254350d58ff3SArtur Paszkiewicz raid_bdev_process_finish_unquiesced, process); 254450d58ff3SArtur Paszkiewicz if (rc != 0) { 254550d58ff3SArtur Paszkiewicz raid_bdev_process_finish_unquiesced(process, rc); 254650d58ff3SArtur Paszkiewicz } 254750d58ff3SArtur Paszkiewicz } 254850d58ff3SArtur Paszkiewicz 254950d58ff3SArtur Paszkiewicz static void 255050d58ff3SArtur Paszkiewicz raid_bdev_process_finish_done(void *ctx) 255150d58ff3SArtur Paszkiewicz { 255250d58ff3SArtur Paszkiewicz struct raid_bdev_process *process = ctx; 255350d58ff3SArtur Paszkiewicz struct raid_bdev *raid_bdev = process->raid_bdev; 255450d58ff3SArtur Paszkiewicz 255550d58ff3SArtur Paszkiewicz if (process->raid_ch != NULL) { 255650d58ff3SArtur Paszkiewicz spdk_put_io_channel(spdk_io_channel_from_ctx(process->raid_ch)); 255750d58ff3SArtur Paszkiewicz } 255850d58ff3SArtur Paszkiewicz 255950d58ff3SArtur Paszkiewicz process->state = RAID_PROCESS_STATE_STOPPED; 256050d58ff3SArtur Paszkiewicz 256150d58ff3SArtur Paszkiewicz if (process->status == 0) { 256250d58ff3SArtur Paszkiewicz SPDK_NOTICELOG("Finished %s on raid bdev %s\n", 256350d58ff3SArtur Paszkiewicz raid_bdev_process_to_str(process->type), 256450d58ff3SArtur Paszkiewicz raid_bdev->bdev.name); 25653bb8256aSArtur Paszkiewicz if (raid_bdev->superblock_enabled) { 256650d58ff3SArtur Paszkiewicz spdk_thread_send_msg(spdk_thread_get_app_thread(), 256750d58ff3SArtur Paszkiewicz raid_bdev_process_finish_write_sb, 256850d58ff3SArtur Paszkiewicz raid_bdev); 256950d58ff3SArtur Paszkiewicz } 257050d58ff3SArtur Paszkiewicz } else { 257150d58ff3SArtur Paszkiewicz SPDK_WARNLOG("Finished %s on raid bdev %s: %s\n", 257250d58ff3SArtur Paszkiewicz raid_bdev_process_to_str(process->type), 257350d58ff3SArtur Paszkiewicz raid_bdev->bdev.name, 257450d58ff3SArtur Paszkiewicz spdk_strerror(-process->status)); 257550d58ff3SArtur Paszkiewicz } 257650d58ff3SArtur Paszkiewicz 257750d58ff3SArtur Paszkiewicz spdk_thread_send_msg(spdk_thread_get_app_thread(), raid_bdev_process_finish_unquiesce, 257850d58ff3SArtur Paszkiewicz process); 257950d58ff3SArtur Paszkiewicz } 258050d58ff3SArtur Paszkiewicz 258150d58ff3SArtur Paszkiewicz static void 258250d58ff3SArtur Paszkiewicz __raid_bdev_process_finish(struct spdk_io_channel_iter *i, int status) 258350d58ff3SArtur Paszkiewicz { 258450d58ff3SArtur Paszkiewicz struct raid_bdev_process *process = spdk_io_channel_iter_get_ctx(i); 258550d58ff3SArtur Paszkiewicz 258650d58ff3SArtur Paszkiewicz spdk_thread_send_msg(process->thread, raid_bdev_process_finish_done, process); 258750d58ff3SArtur Paszkiewicz } 258850d58ff3SArtur Paszkiewicz 258950d58ff3SArtur Paszkiewicz static void 259050d58ff3SArtur Paszkiewicz raid_bdev_channel_process_finish(struct spdk_io_channel_iter *i) 259150d58ff3SArtur Paszkiewicz { 259250d58ff3SArtur Paszkiewicz struct raid_bdev_process *process = spdk_io_channel_iter_get_ctx(i); 259350d58ff3SArtur Paszkiewicz struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(i); 259450d58ff3SArtur Paszkiewicz struct raid_bdev_io_channel *raid_ch = spdk_io_channel_get_ctx(ch); 259550d58ff3SArtur Paszkiewicz 259650d58ff3SArtur Paszkiewicz if (process->status == 0) { 259750d58ff3SArtur Paszkiewicz uint8_t slot = raid_bdev_base_bdev_slot(process->target); 259850d58ff3SArtur Paszkiewicz 259950d58ff3SArtur Paszkiewicz raid_ch->base_channel[slot] = raid_ch->process.target_ch; 260050d58ff3SArtur Paszkiewicz raid_ch->process.target_ch = NULL; 260150d58ff3SArtur Paszkiewicz } 260250d58ff3SArtur Paszkiewicz 260350d58ff3SArtur Paszkiewicz raid_bdev_ch_process_cleanup(raid_ch); 260450d58ff3SArtur Paszkiewicz 260550d58ff3SArtur Paszkiewicz spdk_for_each_channel_continue(i, 0); 260650d58ff3SArtur Paszkiewicz } 260750d58ff3SArtur Paszkiewicz 260850d58ff3SArtur Paszkiewicz static void 260950d58ff3SArtur Paszkiewicz raid_bdev_process_finish_quiesced(void *ctx, int status) 261050d58ff3SArtur Paszkiewicz { 261150d58ff3SArtur Paszkiewicz struct raid_bdev_process *process = ctx; 261250d58ff3SArtur Paszkiewicz struct raid_bdev *raid_bdev = process->raid_bdev; 261350d58ff3SArtur Paszkiewicz 261450d58ff3SArtur Paszkiewicz if (status != 0) { 261550d58ff3SArtur Paszkiewicz SPDK_ERRLOG("Failed to quiesce bdev: %s\n", spdk_strerror(-status)); 261650d58ff3SArtur Paszkiewicz return; 261750d58ff3SArtur Paszkiewicz } 261850d58ff3SArtur Paszkiewicz 261950d58ff3SArtur Paszkiewicz raid_bdev->process = NULL; 2620a6708553SArtur Paszkiewicz process->target->is_process_target = false; 2621a6708553SArtur Paszkiewicz 262250d58ff3SArtur Paszkiewicz spdk_for_each_channel(process->raid_bdev, raid_bdev_channel_process_finish, process, 262350d58ff3SArtur Paszkiewicz __raid_bdev_process_finish); 262450d58ff3SArtur Paszkiewicz } 262550d58ff3SArtur Paszkiewicz 262650d58ff3SArtur Paszkiewicz static void 262750d58ff3SArtur Paszkiewicz _raid_bdev_process_finish(void *ctx) 262850d58ff3SArtur Paszkiewicz { 262950d58ff3SArtur Paszkiewicz struct raid_bdev_process *process = ctx; 263050d58ff3SArtur Paszkiewicz int rc; 263150d58ff3SArtur Paszkiewicz 263250d58ff3SArtur Paszkiewicz rc = spdk_bdev_quiesce(&process->raid_bdev->bdev, &g_raid_if, 263350d58ff3SArtur Paszkiewicz raid_bdev_process_finish_quiesced, process); 263450d58ff3SArtur Paszkiewicz if (rc != 0) { 263550d58ff3SArtur Paszkiewicz raid_bdev_process_finish_quiesced(ctx, rc); 263650d58ff3SArtur Paszkiewicz } 263750d58ff3SArtur Paszkiewicz } 263850d58ff3SArtur Paszkiewicz 263950d58ff3SArtur Paszkiewicz static void 264050d58ff3SArtur Paszkiewicz raid_bdev_process_do_finish(struct raid_bdev_process *process) 264150d58ff3SArtur Paszkiewicz { 264250d58ff3SArtur Paszkiewicz spdk_thread_send_msg(spdk_thread_get_app_thread(), _raid_bdev_process_finish, process); 264350d58ff3SArtur Paszkiewicz } 264450d58ff3SArtur Paszkiewicz 264550d58ff3SArtur Paszkiewicz static void raid_bdev_process_unlock_window_range(struct raid_bdev_process *process); 264650d58ff3SArtur Paszkiewicz static void raid_bdev_process_thread_run(struct raid_bdev_process *process); 264750d58ff3SArtur Paszkiewicz 264850d58ff3SArtur Paszkiewicz static void 264950d58ff3SArtur Paszkiewicz raid_bdev_process_finish(struct raid_bdev_process *process, int status) 265050d58ff3SArtur Paszkiewicz { 265150d58ff3SArtur Paszkiewicz assert(spdk_get_thread() == process->thread); 265250d58ff3SArtur Paszkiewicz 265350d58ff3SArtur Paszkiewicz if (process->status == 0) { 265450d58ff3SArtur Paszkiewicz process->status = status; 265550d58ff3SArtur Paszkiewicz } 265650d58ff3SArtur Paszkiewicz 265750d58ff3SArtur Paszkiewicz if (process->state >= RAID_PROCESS_STATE_STOPPING) { 265850d58ff3SArtur Paszkiewicz return; 265950d58ff3SArtur Paszkiewicz } 266050d58ff3SArtur Paszkiewicz 266150d58ff3SArtur Paszkiewicz assert(process->state == RAID_PROCESS_STATE_RUNNING); 266250d58ff3SArtur Paszkiewicz process->state = RAID_PROCESS_STATE_STOPPING; 266350d58ff3SArtur Paszkiewicz 266450d58ff3SArtur Paszkiewicz if (process->window_range_locked) { 266550d58ff3SArtur Paszkiewicz raid_bdev_process_unlock_window_range(process); 266650d58ff3SArtur Paszkiewicz } else { 266750d58ff3SArtur Paszkiewicz raid_bdev_process_thread_run(process); 266850d58ff3SArtur Paszkiewicz } 266950d58ff3SArtur Paszkiewicz } 267050d58ff3SArtur Paszkiewicz 267150d58ff3SArtur Paszkiewicz static void 267250d58ff3SArtur Paszkiewicz raid_bdev_process_window_range_unlocked(void *ctx, int status) 267350d58ff3SArtur Paszkiewicz { 267450d58ff3SArtur Paszkiewicz struct raid_bdev_process *process = ctx; 267550d58ff3SArtur Paszkiewicz 267650d58ff3SArtur Paszkiewicz if (status != 0) { 267750d58ff3SArtur Paszkiewicz SPDK_ERRLOG("Failed to unlock LBA range: %s\n", spdk_strerror(-status)); 267850d58ff3SArtur Paszkiewicz raid_bdev_process_finish(process, status); 267950d58ff3SArtur Paszkiewicz return; 268050d58ff3SArtur Paszkiewicz } 268150d58ff3SArtur Paszkiewicz 268250d58ff3SArtur Paszkiewicz process->window_range_locked = false; 268350d58ff3SArtur Paszkiewicz process->window_offset += process->window_size; 268450d58ff3SArtur Paszkiewicz 268550d58ff3SArtur Paszkiewicz raid_bdev_process_thread_run(process); 268650d58ff3SArtur Paszkiewicz } 268750d58ff3SArtur Paszkiewicz 268850d58ff3SArtur Paszkiewicz static void 268950d58ff3SArtur Paszkiewicz raid_bdev_process_unlock_window_range(struct raid_bdev_process *process) 269050d58ff3SArtur Paszkiewicz { 269150d58ff3SArtur Paszkiewicz int rc; 269250d58ff3SArtur Paszkiewicz 269350d58ff3SArtur Paszkiewicz assert(process->window_range_locked == true); 269450d58ff3SArtur Paszkiewicz 269550d58ff3SArtur Paszkiewicz rc = spdk_bdev_unquiesce_range(&process->raid_bdev->bdev, &g_raid_if, 269650d58ff3SArtur Paszkiewicz process->window_offset, process->max_window_size, 269750d58ff3SArtur Paszkiewicz raid_bdev_process_window_range_unlocked, process); 269850d58ff3SArtur Paszkiewicz if (rc != 0) { 269950d58ff3SArtur Paszkiewicz raid_bdev_process_window_range_unlocked(process, rc); 270050d58ff3SArtur Paszkiewicz } 270150d58ff3SArtur Paszkiewicz } 270250d58ff3SArtur Paszkiewicz 270350d58ff3SArtur Paszkiewicz static void 270450d58ff3SArtur Paszkiewicz raid_bdev_process_channels_update_done(struct spdk_io_channel_iter *i, int status) 270550d58ff3SArtur Paszkiewicz { 270650d58ff3SArtur Paszkiewicz struct raid_bdev_process *process = spdk_io_channel_iter_get_ctx(i); 270750d58ff3SArtur Paszkiewicz 270850d58ff3SArtur Paszkiewicz raid_bdev_process_unlock_window_range(process); 270950d58ff3SArtur Paszkiewicz } 271050d58ff3SArtur Paszkiewicz 271150d58ff3SArtur Paszkiewicz static void 271250d58ff3SArtur Paszkiewicz raid_bdev_process_channel_update(struct spdk_io_channel_iter *i) 271350d58ff3SArtur Paszkiewicz { 271450d58ff3SArtur Paszkiewicz struct raid_bdev_process *process = spdk_io_channel_iter_get_ctx(i); 271550d58ff3SArtur Paszkiewicz struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(i); 271650d58ff3SArtur Paszkiewicz struct raid_bdev_io_channel *raid_ch = spdk_io_channel_get_ctx(ch); 271750d58ff3SArtur Paszkiewicz 271850d58ff3SArtur Paszkiewicz raid_ch->process.offset = process->window_offset + process->window_size; 271950d58ff3SArtur Paszkiewicz 272050d58ff3SArtur Paszkiewicz spdk_for_each_channel_continue(i, 0); 272150d58ff3SArtur Paszkiewicz } 272250d58ff3SArtur Paszkiewicz 272350d58ff3SArtur Paszkiewicz void 272450d58ff3SArtur Paszkiewicz raid_bdev_process_request_complete(struct raid_bdev_process_request *process_req, int status) 272550d58ff3SArtur Paszkiewicz { 272650d58ff3SArtur Paszkiewicz struct raid_bdev_process *process = process_req->process; 272750d58ff3SArtur Paszkiewicz 272850d58ff3SArtur Paszkiewicz TAILQ_INSERT_TAIL(&process->requests, process_req, link); 272950d58ff3SArtur Paszkiewicz 273050d58ff3SArtur Paszkiewicz assert(spdk_get_thread() == process->thread); 273150d58ff3SArtur Paszkiewicz assert(process->window_remaining >= process_req->num_blocks); 273250d58ff3SArtur Paszkiewicz 273350d58ff3SArtur Paszkiewicz if (status != 0) { 273450d58ff3SArtur Paszkiewicz process->window_status = status; 273550d58ff3SArtur Paszkiewicz } 273650d58ff3SArtur Paszkiewicz 273750d58ff3SArtur Paszkiewicz process->window_remaining -= process_req->num_blocks; 273850d58ff3SArtur Paszkiewicz if (process->window_remaining == 0) { 273950d58ff3SArtur Paszkiewicz if (process->window_status != 0) { 274050d58ff3SArtur Paszkiewicz raid_bdev_process_finish(process, process->window_status); 274150d58ff3SArtur Paszkiewicz return; 274250d58ff3SArtur Paszkiewicz } 274350d58ff3SArtur Paszkiewicz 274450d58ff3SArtur Paszkiewicz spdk_for_each_channel(process->raid_bdev, raid_bdev_process_channel_update, process, 274550d58ff3SArtur Paszkiewicz raid_bdev_process_channels_update_done); 274650d58ff3SArtur Paszkiewicz } 274750d58ff3SArtur Paszkiewicz } 274850d58ff3SArtur Paszkiewicz 274950d58ff3SArtur Paszkiewicz static int 275050d58ff3SArtur Paszkiewicz raid_bdev_submit_process_request(struct raid_bdev_process *process, uint64_t offset_blocks, 275150d58ff3SArtur Paszkiewicz uint32_t num_blocks) 275250d58ff3SArtur Paszkiewicz { 275350d58ff3SArtur Paszkiewicz struct raid_bdev *raid_bdev = process->raid_bdev; 275450d58ff3SArtur Paszkiewicz struct raid_bdev_process_request *process_req; 275550d58ff3SArtur Paszkiewicz int ret; 275650d58ff3SArtur Paszkiewicz 275750d58ff3SArtur Paszkiewicz process_req = TAILQ_FIRST(&process->requests); 275850d58ff3SArtur Paszkiewicz if (process_req == NULL) { 275950d58ff3SArtur Paszkiewicz assert(process->window_remaining > 0); 276050d58ff3SArtur Paszkiewicz return 0; 276150d58ff3SArtur Paszkiewicz } 276250d58ff3SArtur Paszkiewicz 276350d58ff3SArtur Paszkiewicz process_req->target = process->target; 276450d58ff3SArtur Paszkiewicz process_req->target_ch = process->raid_ch->process.target_ch; 276550d58ff3SArtur Paszkiewicz process_req->offset_blocks = offset_blocks; 276650d58ff3SArtur Paszkiewicz process_req->num_blocks = num_blocks; 276750d58ff3SArtur Paszkiewicz process_req->iov.iov_len = num_blocks * raid_bdev->bdev.blocklen; 276850d58ff3SArtur Paszkiewicz 276950d58ff3SArtur Paszkiewicz ret = raid_bdev->module->submit_process_request(process_req, process->raid_ch); 277050d58ff3SArtur Paszkiewicz if (ret <= 0) { 277150d58ff3SArtur Paszkiewicz if (ret < 0) { 277250d58ff3SArtur Paszkiewicz SPDK_ERRLOG("Failed to submit process request on %s: %s\n", 277350d58ff3SArtur Paszkiewicz raid_bdev->bdev.name, spdk_strerror(-ret)); 277450d58ff3SArtur Paszkiewicz process->window_status = ret; 277550d58ff3SArtur Paszkiewicz } 277650d58ff3SArtur Paszkiewicz return ret; 277750d58ff3SArtur Paszkiewicz } 277850d58ff3SArtur Paszkiewicz 277950d58ff3SArtur Paszkiewicz process_req->num_blocks = ret; 278050d58ff3SArtur Paszkiewicz TAILQ_REMOVE(&process->requests, process_req, link); 278150d58ff3SArtur Paszkiewicz 278250d58ff3SArtur Paszkiewicz return ret; 278350d58ff3SArtur Paszkiewicz } 278450d58ff3SArtur Paszkiewicz 278550d58ff3SArtur Paszkiewicz static void 278650d58ff3SArtur Paszkiewicz _raid_bdev_process_thread_run(struct raid_bdev_process *process) 278750d58ff3SArtur Paszkiewicz { 278850d58ff3SArtur Paszkiewicz struct raid_bdev *raid_bdev = process->raid_bdev; 278950d58ff3SArtur Paszkiewicz uint64_t offset = process->window_offset; 279050d58ff3SArtur Paszkiewicz const uint64_t offset_end = spdk_min(offset + process->max_window_size, raid_bdev->bdev.blockcnt); 279150d58ff3SArtur Paszkiewicz int ret; 279250d58ff3SArtur Paszkiewicz 279350d58ff3SArtur Paszkiewicz while (offset < offset_end) { 279450d58ff3SArtur Paszkiewicz ret = raid_bdev_submit_process_request(process, offset, offset_end - offset); 279550d58ff3SArtur Paszkiewicz if (ret <= 0) { 279650d58ff3SArtur Paszkiewicz break; 279750d58ff3SArtur Paszkiewicz } 279850d58ff3SArtur Paszkiewicz 279950d58ff3SArtur Paszkiewicz process->window_remaining += ret; 280050d58ff3SArtur Paszkiewicz offset += ret; 280150d58ff3SArtur Paszkiewicz } 280250d58ff3SArtur Paszkiewicz 280350d58ff3SArtur Paszkiewicz if (process->window_remaining > 0) { 280450d58ff3SArtur Paszkiewicz process->window_size = process->window_remaining; 280550d58ff3SArtur Paszkiewicz } else { 280650d58ff3SArtur Paszkiewicz raid_bdev_process_finish(process, process->window_status); 280750d58ff3SArtur Paszkiewicz } 280850d58ff3SArtur Paszkiewicz } 280950d58ff3SArtur Paszkiewicz 281050d58ff3SArtur Paszkiewicz static void 281150d58ff3SArtur Paszkiewicz raid_bdev_process_window_range_locked(void *ctx, int status) 281250d58ff3SArtur Paszkiewicz { 281350d58ff3SArtur Paszkiewicz struct raid_bdev_process *process = ctx; 281450d58ff3SArtur Paszkiewicz 281550d58ff3SArtur Paszkiewicz if (status != 0) { 281650d58ff3SArtur Paszkiewicz SPDK_ERRLOG("Failed to lock LBA range: %s\n", spdk_strerror(-status)); 281750d58ff3SArtur Paszkiewicz raid_bdev_process_finish(process, status); 281850d58ff3SArtur Paszkiewicz return; 281950d58ff3SArtur Paszkiewicz } 282050d58ff3SArtur Paszkiewicz 282150d58ff3SArtur Paszkiewicz process->window_range_locked = true; 282250d58ff3SArtur Paszkiewicz 282350d58ff3SArtur Paszkiewicz if (process->state == RAID_PROCESS_STATE_STOPPING) { 282450d58ff3SArtur Paszkiewicz raid_bdev_process_unlock_window_range(process); 282550d58ff3SArtur Paszkiewicz return; 282650d58ff3SArtur Paszkiewicz } 282750d58ff3SArtur Paszkiewicz 282850d58ff3SArtur Paszkiewicz _raid_bdev_process_thread_run(process); 282950d58ff3SArtur Paszkiewicz } 283050d58ff3SArtur Paszkiewicz 283189fd1730Sxupeng9 static bool 283289fd1730Sxupeng9 raid_bdev_process_consume_token(struct raid_bdev_process *process) 283389fd1730Sxupeng9 { 283489fd1730Sxupeng9 struct raid_bdev *raid_bdev = process->raid_bdev; 283589fd1730Sxupeng9 uint64_t now = spdk_get_ticks(); 283689fd1730Sxupeng9 283789fd1730Sxupeng9 process->qos.bytes_available = spdk_min(process->qos.bytes_max, 283889fd1730Sxupeng9 process->qos.bytes_available + 283989fd1730Sxupeng9 (now - process->qos.last_tsc) * process->qos.bytes_per_tsc); 284089fd1730Sxupeng9 process->qos.last_tsc = now; 284189fd1730Sxupeng9 if (process->qos.bytes_available > 0.0) { 284289fd1730Sxupeng9 process->qos.bytes_available -= process->window_size * raid_bdev->bdev.blocklen; 284389fd1730Sxupeng9 return true; 284489fd1730Sxupeng9 } 284589fd1730Sxupeng9 return false; 284689fd1730Sxupeng9 } 284789fd1730Sxupeng9 284889fd1730Sxupeng9 static bool 284989fd1730Sxupeng9 raid_bdev_process_lock_window_range(struct raid_bdev_process *process) 285089fd1730Sxupeng9 { 285189fd1730Sxupeng9 struct raid_bdev *raid_bdev = process->raid_bdev; 285289fd1730Sxupeng9 int rc; 285389fd1730Sxupeng9 285489fd1730Sxupeng9 assert(process->window_range_locked == false); 285589fd1730Sxupeng9 285689fd1730Sxupeng9 if (process->qos.enable_qos) { 285789fd1730Sxupeng9 if (raid_bdev_process_consume_token(process)) { 285889fd1730Sxupeng9 spdk_poller_pause(process->qos.process_continue_poller); 285989fd1730Sxupeng9 } else { 286089fd1730Sxupeng9 spdk_poller_resume(process->qos.process_continue_poller); 286189fd1730Sxupeng9 return false; 286289fd1730Sxupeng9 } 286389fd1730Sxupeng9 } 286489fd1730Sxupeng9 286589fd1730Sxupeng9 rc = spdk_bdev_quiesce_range(&raid_bdev->bdev, &g_raid_if, 286689fd1730Sxupeng9 process->window_offset, process->max_window_size, 286789fd1730Sxupeng9 raid_bdev_process_window_range_locked, process); 286889fd1730Sxupeng9 if (rc != 0) { 286989fd1730Sxupeng9 raid_bdev_process_window_range_locked(process, rc); 287089fd1730Sxupeng9 } 287189fd1730Sxupeng9 return true; 287289fd1730Sxupeng9 } 287389fd1730Sxupeng9 287489fd1730Sxupeng9 static int 287589fd1730Sxupeng9 raid_bdev_process_continue_poll(void *arg) 287689fd1730Sxupeng9 { 287789fd1730Sxupeng9 struct raid_bdev_process *process = arg; 287889fd1730Sxupeng9 287989fd1730Sxupeng9 if (raid_bdev_process_lock_window_range(process)) { 288089fd1730Sxupeng9 return SPDK_POLLER_BUSY; 288189fd1730Sxupeng9 } 288289fd1730Sxupeng9 return SPDK_POLLER_IDLE; 288389fd1730Sxupeng9 } 288489fd1730Sxupeng9 288550d58ff3SArtur Paszkiewicz static void 288650d58ff3SArtur Paszkiewicz raid_bdev_process_thread_run(struct raid_bdev_process *process) 288750d58ff3SArtur Paszkiewicz { 288850d58ff3SArtur Paszkiewicz struct raid_bdev *raid_bdev = process->raid_bdev; 288950d58ff3SArtur Paszkiewicz 289050d58ff3SArtur Paszkiewicz assert(spdk_get_thread() == process->thread); 289150d58ff3SArtur Paszkiewicz assert(process->window_remaining == 0); 289250d58ff3SArtur Paszkiewicz assert(process->window_range_locked == false); 289350d58ff3SArtur Paszkiewicz 289450d58ff3SArtur Paszkiewicz if (process->state == RAID_PROCESS_STATE_STOPPING) { 289550d58ff3SArtur Paszkiewicz raid_bdev_process_do_finish(process); 289650d58ff3SArtur Paszkiewicz return; 289750d58ff3SArtur Paszkiewicz } 289850d58ff3SArtur Paszkiewicz 289950d58ff3SArtur Paszkiewicz if (process->window_offset == raid_bdev->bdev.blockcnt) { 290050d58ff3SArtur Paszkiewicz SPDK_DEBUGLOG(bdev_raid, "process completed on %s\n", raid_bdev->bdev.name); 290150d58ff3SArtur Paszkiewicz raid_bdev_process_finish(process, 0); 290250d58ff3SArtur Paszkiewicz return; 290350d58ff3SArtur Paszkiewicz } 290450d58ff3SArtur Paszkiewicz 290550d58ff3SArtur Paszkiewicz process->max_window_size = spdk_min(raid_bdev->bdev.blockcnt - process->window_offset, 290650d58ff3SArtur Paszkiewicz process->max_window_size); 290789fd1730Sxupeng9 raid_bdev_process_lock_window_range(process); 290850d58ff3SArtur Paszkiewicz } 290950d58ff3SArtur Paszkiewicz 291050d58ff3SArtur Paszkiewicz static void 291150d58ff3SArtur Paszkiewicz raid_bdev_process_thread_init(void *ctx) 291250d58ff3SArtur Paszkiewicz { 291350d58ff3SArtur Paszkiewicz struct raid_bdev_process *process = ctx; 291450d58ff3SArtur Paszkiewicz struct raid_bdev *raid_bdev = process->raid_bdev; 291550d58ff3SArtur Paszkiewicz struct spdk_io_channel *ch; 291650d58ff3SArtur Paszkiewicz 291750d58ff3SArtur Paszkiewicz process->thread = spdk_get_thread(); 291850d58ff3SArtur Paszkiewicz 291950d58ff3SArtur Paszkiewicz ch = spdk_get_io_channel(raid_bdev); 292050d58ff3SArtur Paszkiewicz if (ch == NULL) { 292150d58ff3SArtur Paszkiewicz process->status = -ENOMEM; 292250d58ff3SArtur Paszkiewicz raid_bdev_process_do_finish(process); 292350d58ff3SArtur Paszkiewicz return; 292450d58ff3SArtur Paszkiewicz } 292550d58ff3SArtur Paszkiewicz 292650d58ff3SArtur Paszkiewicz process->raid_ch = spdk_io_channel_get_ctx(ch); 292750d58ff3SArtur Paszkiewicz process->state = RAID_PROCESS_STATE_RUNNING; 292850d58ff3SArtur Paszkiewicz 292989fd1730Sxupeng9 if (process->qos.enable_qos) { 293089fd1730Sxupeng9 process->qos.process_continue_poller = SPDK_POLLER_REGISTER(raid_bdev_process_continue_poll, 293189fd1730Sxupeng9 process, 0); 293289fd1730Sxupeng9 spdk_poller_pause(process->qos.process_continue_poller); 293389fd1730Sxupeng9 } 293489fd1730Sxupeng9 293550d58ff3SArtur Paszkiewicz SPDK_NOTICELOG("Started %s on raid bdev %s\n", 293650d58ff3SArtur Paszkiewicz raid_bdev_process_to_str(process->type), raid_bdev->bdev.name); 293750d58ff3SArtur Paszkiewicz 293850d58ff3SArtur Paszkiewicz raid_bdev_process_thread_run(process); 293950d58ff3SArtur Paszkiewicz } 294050d58ff3SArtur Paszkiewicz 294150d58ff3SArtur Paszkiewicz static void 294250d58ff3SArtur Paszkiewicz raid_bdev_channels_abort_start_process_done(struct spdk_io_channel_iter *i, int status) 294350d58ff3SArtur Paszkiewicz { 294450d58ff3SArtur Paszkiewicz struct raid_bdev_process *process = spdk_io_channel_iter_get_ctx(i); 294550d58ff3SArtur Paszkiewicz 294650d58ff3SArtur Paszkiewicz _raid_bdev_remove_base_bdev(process->target, NULL, NULL); 294750d58ff3SArtur Paszkiewicz raid_bdev_process_free(process); 294850d58ff3SArtur Paszkiewicz 294950d58ff3SArtur Paszkiewicz /* TODO: update sb */ 295050d58ff3SArtur Paszkiewicz } 295150d58ff3SArtur Paszkiewicz 295250d58ff3SArtur Paszkiewicz static void 295350d58ff3SArtur Paszkiewicz raid_bdev_channel_abort_start_process(struct spdk_io_channel_iter *i) 295450d58ff3SArtur Paszkiewicz { 295550d58ff3SArtur Paszkiewicz struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(i); 295650d58ff3SArtur Paszkiewicz struct raid_bdev_io_channel *raid_ch = spdk_io_channel_get_ctx(ch); 295750d58ff3SArtur Paszkiewicz 295850d58ff3SArtur Paszkiewicz raid_bdev_ch_process_cleanup(raid_ch); 295950d58ff3SArtur Paszkiewicz 296050d58ff3SArtur Paszkiewicz spdk_for_each_channel_continue(i, 0); 296150d58ff3SArtur Paszkiewicz } 296250d58ff3SArtur Paszkiewicz 296350d58ff3SArtur Paszkiewicz static void 296450d58ff3SArtur Paszkiewicz raid_bdev_channels_start_process_done(struct spdk_io_channel_iter *i, int status) 296550d58ff3SArtur Paszkiewicz { 296650d58ff3SArtur Paszkiewicz struct raid_bdev_process *process = spdk_io_channel_iter_get_ctx(i); 296750d58ff3SArtur Paszkiewicz struct raid_bdev *raid_bdev = process->raid_bdev; 296850d58ff3SArtur Paszkiewicz struct spdk_thread *thread; 296950d58ff3SArtur Paszkiewicz char thread_name[RAID_BDEV_SB_NAME_SIZE + 16]; 297050d58ff3SArtur Paszkiewicz 29711a587504SArtur Paszkiewicz if (status == 0 && 29721a587504SArtur Paszkiewicz (process->target->remove_scheduled || !process->target->is_configured || 29731a587504SArtur Paszkiewicz raid_bdev->num_base_bdevs_operational <= raid_bdev->min_base_bdevs_operational)) { 29741a587504SArtur Paszkiewicz /* a base bdev was removed before we got here */ 29751a587504SArtur Paszkiewicz status = -ENODEV; 29761a587504SArtur Paszkiewicz } 29771a587504SArtur Paszkiewicz 297850d58ff3SArtur Paszkiewicz if (status != 0) { 297950d58ff3SArtur Paszkiewicz SPDK_ERRLOG("Failed to start %s on %s: %s\n", 298050d58ff3SArtur Paszkiewicz raid_bdev_process_to_str(process->type), raid_bdev->bdev.name, 298150d58ff3SArtur Paszkiewicz spdk_strerror(-status)); 298250d58ff3SArtur Paszkiewicz goto err; 298350d58ff3SArtur Paszkiewicz } 298450d58ff3SArtur Paszkiewicz 298550d58ff3SArtur Paszkiewicz snprintf(thread_name, sizeof(thread_name), "%s_%s", 298650d58ff3SArtur Paszkiewicz raid_bdev->bdev.name, raid_bdev_process_to_str(process->type)); 298750d58ff3SArtur Paszkiewicz 298850d58ff3SArtur Paszkiewicz thread = spdk_thread_create(thread_name, NULL); 298950d58ff3SArtur Paszkiewicz if (thread == NULL) { 299050d58ff3SArtur Paszkiewicz SPDK_ERRLOG("Failed to create %s thread for %s\n", 299150d58ff3SArtur Paszkiewicz raid_bdev_process_to_str(process->type), raid_bdev->bdev.name); 299250d58ff3SArtur Paszkiewicz goto err; 299350d58ff3SArtur Paszkiewicz } 299450d58ff3SArtur Paszkiewicz 299550d58ff3SArtur Paszkiewicz raid_bdev->process = process; 299650d58ff3SArtur Paszkiewicz 299750d58ff3SArtur Paszkiewicz spdk_thread_send_msg(thread, raid_bdev_process_thread_init, process); 299850d58ff3SArtur Paszkiewicz 299950d58ff3SArtur Paszkiewicz return; 300050d58ff3SArtur Paszkiewicz err: 300150d58ff3SArtur Paszkiewicz spdk_for_each_channel(process->raid_bdev, raid_bdev_channel_abort_start_process, process, 300250d58ff3SArtur Paszkiewicz raid_bdev_channels_abort_start_process_done); 300350d58ff3SArtur Paszkiewicz } 300450d58ff3SArtur Paszkiewicz 300550d58ff3SArtur Paszkiewicz static void 300650d58ff3SArtur Paszkiewicz raid_bdev_channel_start_process(struct spdk_io_channel_iter *i) 300750d58ff3SArtur Paszkiewicz { 300850d58ff3SArtur Paszkiewicz struct raid_bdev_process *process = spdk_io_channel_iter_get_ctx(i); 300950d58ff3SArtur Paszkiewicz struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(i); 301050d58ff3SArtur Paszkiewicz struct raid_bdev_io_channel *raid_ch = spdk_io_channel_get_ctx(ch); 301150d58ff3SArtur Paszkiewicz int rc; 301250d58ff3SArtur Paszkiewicz 301350d58ff3SArtur Paszkiewicz rc = raid_bdev_ch_process_setup(raid_ch, process); 301450d58ff3SArtur Paszkiewicz 301550d58ff3SArtur Paszkiewicz spdk_for_each_channel_continue(i, rc); 301650d58ff3SArtur Paszkiewicz } 301750d58ff3SArtur Paszkiewicz 301850d58ff3SArtur Paszkiewicz static void 301950d58ff3SArtur Paszkiewicz raid_bdev_process_start(struct raid_bdev_process *process) 302050d58ff3SArtur Paszkiewicz { 302150d58ff3SArtur Paszkiewicz struct raid_bdev *raid_bdev = process->raid_bdev; 302250d58ff3SArtur Paszkiewicz 302350d58ff3SArtur Paszkiewicz assert(raid_bdev->module->submit_process_request != NULL); 302450d58ff3SArtur Paszkiewicz 302550d58ff3SArtur Paszkiewicz spdk_for_each_channel(raid_bdev, raid_bdev_channel_start_process, process, 302650d58ff3SArtur Paszkiewicz raid_bdev_channels_start_process_done); 302750d58ff3SArtur Paszkiewicz } 302850d58ff3SArtur Paszkiewicz 302950d58ff3SArtur Paszkiewicz static void 303050d58ff3SArtur Paszkiewicz raid_bdev_process_request_free(struct raid_bdev_process_request *process_req) 303150d58ff3SArtur Paszkiewicz { 303250d58ff3SArtur Paszkiewicz spdk_dma_free(process_req->iov.iov_base); 303350d58ff3SArtur Paszkiewicz spdk_dma_free(process_req->md_buf); 303450d58ff3SArtur Paszkiewicz free(process_req); 303550d58ff3SArtur Paszkiewicz } 303650d58ff3SArtur Paszkiewicz 303750d58ff3SArtur Paszkiewicz static struct raid_bdev_process_request * 303850d58ff3SArtur Paszkiewicz raid_bdev_process_alloc_request(struct raid_bdev_process *process) 303950d58ff3SArtur Paszkiewicz { 304050d58ff3SArtur Paszkiewicz struct raid_bdev *raid_bdev = process->raid_bdev; 304150d58ff3SArtur Paszkiewicz struct raid_bdev_process_request *process_req; 304250d58ff3SArtur Paszkiewicz 304350d58ff3SArtur Paszkiewicz process_req = calloc(1, sizeof(*process_req)); 304450d58ff3SArtur Paszkiewicz if (process_req == NULL) { 304550d58ff3SArtur Paszkiewicz return NULL; 304650d58ff3SArtur Paszkiewicz } 304750d58ff3SArtur Paszkiewicz 304850d58ff3SArtur Paszkiewicz process_req->process = process; 304950d58ff3SArtur Paszkiewicz process_req->iov.iov_len = process->max_window_size * raid_bdev->bdev.blocklen; 305050d58ff3SArtur Paszkiewicz process_req->iov.iov_base = spdk_dma_malloc(process_req->iov.iov_len, 4096, 0); 305150d58ff3SArtur Paszkiewicz if (process_req->iov.iov_base == NULL) { 305250d58ff3SArtur Paszkiewicz free(process_req); 305350d58ff3SArtur Paszkiewicz return NULL; 305450d58ff3SArtur Paszkiewicz } 305550d58ff3SArtur Paszkiewicz if (spdk_bdev_is_md_separate(&raid_bdev->bdev)) { 305650d58ff3SArtur Paszkiewicz process_req->md_buf = spdk_dma_malloc(process->max_window_size * raid_bdev->bdev.md_len, 4096, 0); 305750d58ff3SArtur Paszkiewicz if (process_req->md_buf == NULL) { 305850d58ff3SArtur Paszkiewicz raid_bdev_process_request_free(process_req); 305950d58ff3SArtur Paszkiewicz return NULL; 306050d58ff3SArtur Paszkiewicz } 306150d58ff3SArtur Paszkiewicz } 306250d58ff3SArtur Paszkiewicz 306350d58ff3SArtur Paszkiewicz return process_req; 306450d58ff3SArtur Paszkiewicz } 306550d58ff3SArtur Paszkiewicz 306650d58ff3SArtur Paszkiewicz static void 306750d58ff3SArtur Paszkiewicz raid_bdev_process_free(struct raid_bdev_process *process) 306850d58ff3SArtur Paszkiewicz { 306950d58ff3SArtur Paszkiewicz struct raid_bdev_process_request *process_req; 307050d58ff3SArtur Paszkiewicz 307150d58ff3SArtur Paszkiewicz while ((process_req = TAILQ_FIRST(&process->requests)) != NULL) { 307250d58ff3SArtur Paszkiewicz TAILQ_REMOVE(&process->requests, process_req, link); 307350d58ff3SArtur Paszkiewicz raid_bdev_process_request_free(process_req); 307450d58ff3SArtur Paszkiewicz } 307550d58ff3SArtur Paszkiewicz 307650d58ff3SArtur Paszkiewicz free(process); 307750d58ff3SArtur Paszkiewicz } 307850d58ff3SArtur Paszkiewicz 307950d58ff3SArtur Paszkiewicz static struct raid_bdev_process * 308050d58ff3SArtur Paszkiewicz raid_bdev_process_alloc(struct raid_bdev *raid_bdev, enum raid_process_type type, 308150d58ff3SArtur Paszkiewicz struct raid_base_bdev_info *target) 308250d58ff3SArtur Paszkiewicz { 308350d58ff3SArtur Paszkiewicz struct raid_bdev_process *process; 308450d58ff3SArtur Paszkiewicz struct raid_bdev_process_request *process_req; 308550d58ff3SArtur Paszkiewicz int i; 308650d58ff3SArtur Paszkiewicz 308750d58ff3SArtur Paszkiewicz process = calloc(1, sizeof(*process)); 308850d58ff3SArtur Paszkiewicz if (process == NULL) { 308950d58ff3SArtur Paszkiewicz return NULL; 309050d58ff3SArtur Paszkiewicz } 309150d58ff3SArtur Paszkiewicz 309250d58ff3SArtur Paszkiewicz process->raid_bdev = raid_bdev; 309350d58ff3SArtur Paszkiewicz process->type = type; 309450d58ff3SArtur Paszkiewicz process->target = target; 3095f39350beSArtur Paszkiewicz process->max_window_size = spdk_max(spdk_divide_round_up(g_opts.process_window_size_kb * 1024UL, 3096bb374988SArtur Paszkiewicz spdk_bdev_get_data_block_size(&raid_bdev->bdev)), 309750d58ff3SArtur Paszkiewicz raid_bdev->bdev.write_unit_size); 309850d58ff3SArtur Paszkiewicz TAILQ_INIT(&process->requests); 30999d2b7b41SArtur Paszkiewicz TAILQ_INIT(&process->finish_actions); 310050d58ff3SArtur Paszkiewicz 310189fd1730Sxupeng9 if (g_opts.process_max_bandwidth_mb_sec != 0) { 310289fd1730Sxupeng9 process->qos.enable_qos = true; 310389fd1730Sxupeng9 process->qos.last_tsc = spdk_get_ticks(); 310489fd1730Sxupeng9 process->qos.bytes_per_tsc = g_opts.process_max_bandwidth_mb_sec * 1024 * 1024.0 / 310589fd1730Sxupeng9 spdk_get_ticks_hz(); 310689fd1730Sxupeng9 process->qos.bytes_max = g_opts.process_max_bandwidth_mb_sec * 1024 * 1024.0 / SPDK_SEC_TO_MSEC; 310789fd1730Sxupeng9 process->qos.bytes_available = 0.0; 310889fd1730Sxupeng9 } 310989fd1730Sxupeng9 311050d58ff3SArtur Paszkiewicz for (i = 0; i < RAID_BDEV_PROCESS_MAX_QD; i++) { 311150d58ff3SArtur Paszkiewicz process_req = raid_bdev_process_alloc_request(process); 311250d58ff3SArtur Paszkiewicz if (process_req == NULL) { 311350d58ff3SArtur Paszkiewicz raid_bdev_process_free(process); 311450d58ff3SArtur Paszkiewicz return NULL; 311550d58ff3SArtur Paszkiewicz } 311650d58ff3SArtur Paszkiewicz 311750d58ff3SArtur Paszkiewicz TAILQ_INSERT_TAIL(&process->requests, process_req, link); 311850d58ff3SArtur Paszkiewicz } 311950d58ff3SArtur Paszkiewicz 312050d58ff3SArtur Paszkiewicz return process; 312150d58ff3SArtur Paszkiewicz } 312250d58ff3SArtur Paszkiewicz 312350d58ff3SArtur Paszkiewicz static int 312450d58ff3SArtur Paszkiewicz raid_bdev_start_rebuild(struct raid_base_bdev_info *target) 312550d58ff3SArtur Paszkiewicz { 312650d58ff3SArtur Paszkiewicz struct raid_bdev_process *process; 312750d58ff3SArtur Paszkiewicz 312850d58ff3SArtur Paszkiewicz assert(spdk_get_thread() == spdk_thread_get_app_thread()); 312950d58ff3SArtur Paszkiewicz 313050d58ff3SArtur Paszkiewicz process = raid_bdev_process_alloc(target->raid_bdev, RAID_PROCESS_REBUILD, target); 313150d58ff3SArtur Paszkiewicz if (process == NULL) { 313250d58ff3SArtur Paszkiewicz return -ENOMEM; 313350d58ff3SArtur Paszkiewicz } 313450d58ff3SArtur Paszkiewicz 313550d58ff3SArtur Paszkiewicz raid_bdev_process_start(process); 313650d58ff3SArtur Paszkiewicz 313750d58ff3SArtur Paszkiewicz return 0; 313850d58ff3SArtur Paszkiewicz } 313950d58ff3SArtur Paszkiewicz 3140a6708553SArtur Paszkiewicz static void raid_bdev_configure_base_bdev_cont(struct raid_base_bdev_info *base_info); 3141a6708553SArtur Paszkiewicz 3142a6708553SArtur Paszkiewicz static void 3143a6708553SArtur Paszkiewicz _raid_bdev_configure_base_bdev_cont(struct spdk_io_channel_iter *i, int status) 3144a6708553SArtur Paszkiewicz { 3145a6708553SArtur Paszkiewicz struct raid_base_bdev_info *base_info = spdk_io_channel_iter_get_ctx(i); 3146a6708553SArtur Paszkiewicz 3147a6708553SArtur Paszkiewicz raid_bdev_configure_base_bdev_cont(base_info); 3148a6708553SArtur Paszkiewicz } 3149a6708553SArtur Paszkiewicz 3150a6708553SArtur Paszkiewicz static void 3151a6708553SArtur Paszkiewicz raid_bdev_ch_sync(struct spdk_io_channel_iter *i) 3152a6708553SArtur Paszkiewicz { 3153a6708553SArtur Paszkiewicz spdk_for_each_channel_continue(i, 0); 3154a6708553SArtur Paszkiewicz } 3155a6708553SArtur Paszkiewicz 315650d58ff3SArtur Paszkiewicz static void 31579222ff97SArtur Paszkiewicz raid_bdev_configure_base_bdev_cont(struct raid_base_bdev_info *base_info) 31589222ff97SArtur Paszkiewicz { 31599222ff97SArtur Paszkiewicz struct raid_bdev *raid_bdev = base_info->raid_bdev; 3160fc2398dfSArtur Paszkiewicz raid_base_bdev_cb configure_cb; 31619222ff97SArtur Paszkiewicz int rc; 31629222ff97SArtur Paszkiewicz 3163a6708553SArtur Paszkiewicz if (raid_bdev->num_base_bdevs_discovered == raid_bdev->num_base_bdevs_operational && 3164a6708553SArtur Paszkiewicz base_info->is_process_target == false) { 316550d58ff3SArtur Paszkiewicz /* TODO: defer if rebuild in progress on another base bdev */ 316650d58ff3SArtur Paszkiewicz assert(raid_bdev->process == NULL); 3167a6708553SArtur Paszkiewicz assert(raid_bdev->state == RAID_BDEV_STATE_ONLINE); 3168a6708553SArtur Paszkiewicz base_info->is_process_target = true; 3169a6708553SArtur Paszkiewicz /* To assure is_process_target is set before is_configured when checked in raid_bdev_create_cb() */ 3170a6708553SArtur Paszkiewicz spdk_for_each_channel(raid_bdev, raid_bdev_ch_sync, base_info, _raid_bdev_configure_base_bdev_cont); 3171a6708553SArtur Paszkiewicz return; 3172a6708553SArtur Paszkiewicz } 317350d58ff3SArtur Paszkiewicz 31749222ff97SArtur Paszkiewicz base_info->is_configured = true; 31759222ff97SArtur Paszkiewicz 31769222ff97SArtur Paszkiewicz raid_bdev->num_base_bdevs_discovered++; 31779222ff97SArtur Paszkiewicz assert(raid_bdev->num_base_bdevs_discovered <= raid_bdev->num_base_bdevs); 3178255d0786SArtur Paszkiewicz assert(raid_bdev->num_base_bdevs_operational <= raid_bdev->num_base_bdevs); 3179255d0786SArtur Paszkiewicz assert(raid_bdev->num_base_bdevs_operational >= raid_bdev->min_base_bdevs_operational); 31809222ff97SArtur Paszkiewicz 3181fc2398dfSArtur Paszkiewicz configure_cb = base_info->configure_cb; 3182fc2398dfSArtur Paszkiewicz base_info->configure_cb = NULL; 3183255d0786SArtur Paszkiewicz /* 3184255d0786SArtur Paszkiewicz * Configure the raid bdev when the number of discovered base bdevs reaches the number 3185255d0786SArtur Paszkiewicz * of base bdevs we know to be operational members of the array. Usually this is equal 3186255d0786SArtur Paszkiewicz * to the total number of base bdevs (num_base_bdevs) but can be less - when the array is 3187255d0786SArtur Paszkiewicz * degraded. 3188255d0786SArtur Paszkiewicz */ 3189255d0786SArtur Paszkiewicz if (raid_bdev->num_base_bdevs_discovered == raid_bdev->num_base_bdevs_operational) { 3190fc2398dfSArtur Paszkiewicz rc = raid_bdev_configure(raid_bdev, configure_cb, base_info->configure_cb_ctx); 31919222ff97SArtur Paszkiewicz if (rc != 0) { 31929222ff97SArtur Paszkiewicz SPDK_ERRLOG("Failed to configure raid bdev: %s\n", spdk_strerror(-rc)); 31935558f3f5SArtur Paszkiewicz } else { 3194fc2398dfSArtur Paszkiewicz configure_cb = NULL; 31959222ff97SArtur Paszkiewicz } 3196a6708553SArtur Paszkiewicz } else if (base_info->is_process_target) { 319750d58ff3SArtur Paszkiewicz raid_bdev->num_base_bdevs_operational++; 319850d58ff3SArtur Paszkiewicz rc = raid_bdev_start_rebuild(base_info); 319950d58ff3SArtur Paszkiewicz if (rc != 0) { 320050d58ff3SArtur Paszkiewicz SPDK_ERRLOG("Failed to start rebuild: %s\n", spdk_strerror(-rc)); 320150d58ff3SArtur Paszkiewicz _raid_bdev_remove_base_bdev(base_info, NULL, NULL); 320250d58ff3SArtur Paszkiewicz } 3203887b8ec4SArtur Paszkiewicz } else { 3204887b8ec4SArtur Paszkiewicz rc = 0; 3205887b8ec4SArtur Paszkiewicz } 3206887b8ec4SArtur Paszkiewicz 3207fc2398dfSArtur Paszkiewicz if (configure_cb != NULL) { 3208fc2398dfSArtur Paszkiewicz configure_cb(base_info->configure_cb_ctx, rc); 32099222ff97SArtur Paszkiewicz } 32109222ff97SArtur Paszkiewicz } 32119222ff97SArtur Paszkiewicz 3212dafdb289SArtur Paszkiewicz static void raid_bdev_examine_sb(const struct raid_bdev_superblock *sb, struct spdk_bdev *bdev, 3213dafdb289SArtur Paszkiewicz raid_base_bdev_cb cb_fn, void *cb_ctx); 3214dafdb289SArtur Paszkiewicz 32159222ff97SArtur Paszkiewicz static void 32169222ff97SArtur Paszkiewicz raid_bdev_configure_base_bdev_check_sb_cb(const struct raid_bdev_superblock *sb, int status, 32179222ff97SArtur Paszkiewicz void *ctx) 32189222ff97SArtur Paszkiewicz { 32199222ff97SArtur Paszkiewicz struct raid_base_bdev_info *base_info = ctx; 3220fc2398dfSArtur Paszkiewicz raid_base_bdev_cb configure_cb = base_info->configure_cb; 32219222ff97SArtur Paszkiewicz 32229222ff97SArtur Paszkiewicz switch (status) { 32239222ff97SArtur Paszkiewicz case 0: 32249222ff97SArtur Paszkiewicz /* valid superblock found */ 3225fc2398dfSArtur Paszkiewicz base_info->configure_cb = NULL; 3226dafdb289SArtur Paszkiewicz if (spdk_uuid_compare(&base_info->raid_bdev->bdev.uuid, &sb->uuid) == 0) { 3227dafdb289SArtur Paszkiewicz struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(base_info->desc); 3228dafdb289SArtur Paszkiewicz 3229dafdb289SArtur Paszkiewicz raid_bdev_free_base_bdev_resource(base_info); 3230fc2398dfSArtur Paszkiewicz raid_bdev_examine_sb(sb, bdev, configure_cb, base_info->configure_cb_ctx); 3231dafdb289SArtur Paszkiewicz return; 3232dafdb289SArtur Paszkiewicz } 3233dafdb289SArtur Paszkiewicz SPDK_ERRLOG("Superblock of a different raid bdev found on bdev %s\n", base_info->name); 3234887b8ec4SArtur Paszkiewicz status = -EEXIST; 32359222ff97SArtur Paszkiewicz raid_bdev_free_base_bdev_resource(base_info); 32369222ff97SArtur Paszkiewicz break; 32379222ff97SArtur Paszkiewicz case -EINVAL: 32389222ff97SArtur Paszkiewicz /* no valid superblock */ 32399222ff97SArtur Paszkiewicz raid_bdev_configure_base_bdev_cont(base_info); 3240887b8ec4SArtur Paszkiewicz return; 32419222ff97SArtur Paszkiewicz default: 32429222ff97SArtur Paszkiewicz SPDK_ERRLOG("Failed to examine bdev %s: %s\n", 32439222ff97SArtur Paszkiewicz base_info->name, spdk_strerror(-status)); 32449222ff97SArtur Paszkiewicz break; 32459222ff97SArtur Paszkiewicz } 3246887b8ec4SArtur Paszkiewicz 3247fc2398dfSArtur Paszkiewicz if (configure_cb != NULL) { 3248fc2398dfSArtur Paszkiewicz base_info->configure_cb = NULL; 3249fc2398dfSArtur Paszkiewicz configure_cb(base_info->configure_cb_ctx, status); 3250887b8ec4SArtur Paszkiewicz } 32519222ff97SArtur Paszkiewicz } 32529222ff97SArtur Paszkiewicz 325307fe6a43SSeth Howell static int 3254887b8ec4SArtur Paszkiewicz raid_bdev_configure_base_bdev(struct raid_base_bdev_info *base_info, bool existing, 3255887b8ec4SArtur Paszkiewicz raid_base_bdev_cb cb_fn, void *cb_ctx) 325607fe6a43SSeth Howell { 325726861b70SArtur Paszkiewicz struct raid_bdev *raid_bdev = base_info->raid_bdev; 3258dccdd1e5SArtur Paszkiewicz struct spdk_bdev_desc *desc; 3259dccdd1e5SArtur Paszkiewicz struct spdk_bdev *bdev; 32608a6bb6a8SArtur Paszkiewicz const struct spdk_uuid *bdev_uuid; 326107fe6a43SSeth Howell int rc; 326207fe6a43SSeth Howell 32634dd2a0d3SArtur Paszkiewicz assert(spdk_get_thread() == spdk_thread_get_app_thread()); 32648d1993a5SArtur Paszkiewicz assert(base_info->desc == NULL); 326507fe6a43SSeth Howell 32668a6bb6a8SArtur Paszkiewicz /* 32678a6bb6a8SArtur Paszkiewicz * Base bdev can be added by name or uuid. Here we assure both properties are set and valid 32688a6bb6a8SArtur Paszkiewicz * before claiming the bdev. 32698a6bb6a8SArtur Paszkiewicz */ 32708a6bb6a8SArtur Paszkiewicz 32718a6bb6a8SArtur Paszkiewicz if (!spdk_uuid_is_null(&base_info->uuid)) { 32728a6bb6a8SArtur Paszkiewicz char uuid_str[SPDK_UUID_STRING_LEN]; 32738a6bb6a8SArtur Paszkiewicz const char *bdev_name; 32748a6bb6a8SArtur Paszkiewicz 32758a6bb6a8SArtur Paszkiewicz spdk_uuid_fmt_lower(uuid_str, sizeof(uuid_str), &base_info->uuid); 32768a6bb6a8SArtur Paszkiewicz 32778a6bb6a8SArtur Paszkiewicz /* UUID of a bdev is registered as its alias */ 32788a6bb6a8SArtur Paszkiewicz bdev = spdk_bdev_get_by_name(uuid_str); 32798a6bb6a8SArtur Paszkiewicz if (bdev == NULL) { 32808a6bb6a8SArtur Paszkiewicz return -ENODEV; 32818a6bb6a8SArtur Paszkiewicz } 32828a6bb6a8SArtur Paszkiewicz 32838a6bb6a8SArtur Paszkiewicz bdev_name = spdk_bdev_get_name(bdev); 32848a6bb6a8SArtur Paszkiewicz 32858a6bb6a8SArtur Paszkiewicz if (base_info->name == NULL) { 32869222ff97SArtur Paszkiewicz assert(existing == true); 32878a6bb6a8SArtur Paszkiewicz base_info->name = strdup(bdev_name); 32888a6bb6a8SArtur Paszkiewicz if (base_info->name == NULL) { 32898a6bb6a8SArtur Paszkiewicz return -ENOMEM; 32908a6bb6a8SArtur Paszkiewicz } 32918a6bb6a8SArtur Paszkiewicz } else if (strcmp(base_info->name, bdev_name) != 0) { 32928a6bb6a8SArtur Paszkiewicz SPDK_ERRLOG("Name mismatch for base bdev '%s' - expected '%s'\n", 32938a6bb6a8SArtur Paszkiewicz bdev_name, base_info->name); 32948a6bb6a8SArtur Paszkiewicz return -EINVAL; 32958a6bb6a8SArtur Paszkiewicz } 32968a6bb6a8SArtur Paszkiewicz } 32978a6bb6a8SArtur Paszkiewicz 32988a6bb6a8SArtur Paszkiewicz assert(base_info->name != NULL); 32998a6bb6a8SArtur Paszkiewicz 3300dccdd1e5SArtur Paszkiewicz rc = spdk_bdev_open_ext(base_info->name, true, raid_bdev_event_base_bdev, NULL, &desc); 330107fe6a43SSeth Howell if (rc != 0) { 3302bd190d88SShuhei Matsumoto if (rc != -ENODEV) { 3303dccdd1e5SArtur Paszkiewicz SPDK_ERRLOG("Unable to create desc on bdev '%s'\n", base_info->name); 3304bd190d88SShuhei Matsumoto } 330507fe6a43SSeth Howell return rc; 330607fe6a43SSeth Howell } 330707fe6a43SSeth Howell 3308dccdd1e5SArtur Paszkiewicz bdev = spdk_bdev_desc_get_bdev(desc); 33098a6bb6a8SArtur Paszkiewicz bdev_uuid = spdk_bdev_get_uuid(bdev); 33108a6bb6a8SArtur Paszkiewicz 33118a6bb6a8SArtur Paszkiewicz if (spdk_uuid_is_null(&base_info->uuid)) { 33128a6bb6a8SArtur Paszkiewicz spdk_uuid_copy(&base_info->uuid, bdev_uuid); 33138a6bb6a8SArtur Paszkiewicz } else if (spdk_uuid_compare(&base_info->uuid, bdev_uuid) != 0) { 33148a6bb6a8SArtur Paszkiewicz SPDK_ERRLOG("UUID mismatch for base bdev '%s'\n", base_info->name); 33158a6bb6a8SArtur Paszkiewicz spdk_bdev_close(desc); 33168a6bb6a8SArtur Paszkiewicz return -EINVAL; 33178a6bb6a8SArtur Paszkiewicz } 3318dccdd1e5SArtur Paszkiewicz 3319dccdd1e5SArtur Paszkiewicz rc = spdk_bdev_module_claim_bdev(bdev, NULL, &g_raid_if); 3320dccdd1e5SArtur Paszkiewicz if (rc != 0) { 3321dccdd1e5SArtur Paszkiewicz SPDK_ERRLOG("Unable to claim this bdev as it is already claimed\n"); 3322dccdd1e5SArtur Paszkiewicz spdk_bdev_close(desc); 3323dccdd1e5SArtur Paszkiewicz return rc; 3324dccdd1e5SArtur Paszkiewicz } 3325dccdd1e5SArtur Paszkiewicz 3326dccdd1e5SArtur Paszkiewicz SPDK_DEBUGLOG(bdev_raid, "bdev %s is claimed\n", bdev->name); 3327dccdd1e5SArtur Paszkiewicz 332877b8f7b6SArtur Paszkiewicz base_info->app_thread_ch = spdk_bdev_get_io_channel(desc); 332977b8f7b6SArtur Paszkiewicz if (base_info->app_thread_ch == NULL) { 333077b8f7b6SArtur Paszkiewicz SPDK_ERRLOG("Failed to get io channel\n"); 333177b8f7b6SArtur Paszkiewicz spdk_bdev_module_release_bdev(bdev); 333277b8f7b6SArtur Paszkiewicz spdk_bdev_close(desc); 333377b8f7b6SArtur Paszkiewicz return -ENOMEM; 333477b8f7b6SArtur Paszkiewicz } 333577b8f7b6SArtur Paszkiewicz 3336dccdd1e5SArtur Paszkiewicz base_info->desc = desc; 3337c9224e26SShuhei Matsumoto base_info->blockcnt = bdev->blockcnt; 333807fe6a43SSeth Howell 33393bb8256aSArtur Paszkiewicz if (raid_bdev->superblock_enabled) { 33408a6bb6a8SArtur Paszkiewicz uint64_t data_offset; 3341deed7d2fSArtur Paszkiewicz 33428a6bb6a8SArtur Paszkiewicz if (base_info->data_offset == 0) { 3343bb374988SArtur Paszkiewicz assert((RAID_BDEV_MIN_DATA_OFFSET_SIZE % spdk_bdev_get_data_block_size(bdev)) == 0); 3344bb374988SArtur Paszkiewicz data_offset = RAID_BDEV_MIN_DATA_OFFSET_SIZE / spdk_bdev_get_data_block_size(bdev); 33458a6bb6a8SArtur Paszkiewicz } else { 33468a6bb6a8SArtur Paszkiewicz data_offset = base_info->data_offset; 33478a6bb6a8SArtur Paszkiewicz } 33488a6bb6a8SArtur Paszkiewicz 33498a6bb6a8SArtur Paszkiewicz if (bdev->optimal_io_boundary != 0) { 33508a6bb6a8SArtur Paszkiewicz data_offset = spdk_divide_round_up(data_offset, 3351deed7d2fSArtur Paszkiewicz bdev->optimal_io_boundary) * bdev->optimal_io_boundary; 33528a6bb6a8SArtur Paszkiewicz if (base_info->data_offset != 0 && base_info->data_offset != data_offset) { 33538a6bb6a8SArtur Paszkiewicz SPDK_WARNLOG("Data offset %lu on bdev '%s' is different than optimal value %lu\n", 33548a6bb6a8SArtur Paszkiewicz base_info->data_offset, base_info->name, data_offset); 33558a6bb6a8SArtur Paszkiewicz data_offset = base_info->data_offset; 33568a6bb6a8SArtur Paszkiewicz } 33578a6bb6a8SArtur Paszkiewicz } 33588a6bb6a8SArtur Paszkiewicz 33598a6bb6a8SArtur Paszkiewicz base_info->data_offset = data_offset; 3360deed7d2fSArtur Paszkiewicz } 3361deed7d2fSArtur Paszkiewicz 3362deed7d2fSArtur Paszkiewicz if (base_info->data_offset >= bdev->blockcnt) { 3363deed7d2fSArtur Paszkiewicz SPDK_ERRLOG("Data offset %lu exceeds base bdev capacity %lu on bdev '%s'\n", 3364deed7d2fSArtur Paszkiewicz base_info->data_offset, bdev->blockcnt, base_info->name); 33658a6bb6a8SArtur Paszkiewicz rc = -EINVAL; 33668a6bb6a8SArtur Paszkiewicz goto out; 3367deed7d2fSArtur Paszkiewicz } 3368deed7d2fSArtur Paszkiewicz 33698a6bb6a8SArtur Paszkiewicz if (base_info->data_size == 0) { 3370deed7d2fSArtur Paszkiewicz base_info->data_size = bdev->blockcnt - base_info->data_offset; 33718a6bb6a8SArtur Paszkiewicz } else if (base_info->data_offset + base_info->data_size > bdev->blockcnt) { 33728a6bb6a8SArtur Paszkiewicz SPDK_ERRLOG("Data offset and size exceeds base bdev capacity %lu on bdev '%s'\n", 33738a6bb6a8SArtur Paszkiewicz bdev->blockcnt, base_info->name); 33748a6bb6a8SArtur Paszkiewicz rc = -EINVAL; 33758a6bb6a8SArtur Paszkiewicz goto out; 3376deed7d2fSArtur Paszkiewicz } 3377deed7d2fSArtur Paszkiewicz 3378192db8deSSlawomir Ptak if (!raid_bdev->module->dif_supported && spdk_bdev_get_dif_type(bdev) != SPDK_DIF_DISABLE) { 3379895d8b56SArtur Paszkiewicz SPDK_ERRLOG("Base bdev '%s' has DIF or DIX enabled - unsupported RAID configuration\n", 3380895d8b56SArtur Paszkiewicz bdev->name); 3381895d8b56SArtur Paszkiewicz rc = -EINVAL; 3382895d8b56SArtur Paszkiewicz goto out; 3383895d8b56SArtur Paszkiewicz } 3384895d8b56SArtur Paszkiewicz 3385895d8b56SArtur Paszkiewicz /* 3386895d8b56SArtur Paszkiewicz * Set the raid bdev properties if this is the first base bdev configured, 3387895d8b56SArtur Paszkiewicz * otherwise - verify. Assumption is that all the base bdevs for any raid bdev should 3388895d8b56SArtur Paszkiewicz * have the same blocklen and metadata format. 3389895d8b56SArtur Paszkiewicz */ 33901c0f3504SArtur Paszkiewicz if (raid_bdev->bdev.blocklen == 0) { 3391895d8b56SArtur Paszkiewicz raid_bdev->bdev.blocklen = bdev->blocklen; 3392895d8b56SArtur Paszkiewicz raid_bdev->bdev.md_len = spdk_bdev_get_md_size(bdev); 3393895d8b56SArtur Paszkiewicz raid_bdev->bdev.md_interleave = spdk_bdev_is_md_interleaved(bdev); 3394192db8deSSlawomir Ptak raid_bdev->bdev.dif_type = spdk_bdev_get_dif_type(bdev); 3395192db8deSSlawomir Ptak raid_bdev->bdev.dif_check_flags = bdev->dif_check_flags; 3396192db8deSSlawomir Ptak raid_bdev->bdev.dif_is_head_of_md = spdk_bdev_is_dif_head_of_md(bdev); 3397fcf59a6fSShuhei Matsumoto raid_bdev->bdev.dif_pi_format = bdev->dif_pi_format; 3398895d8b56SArtur Paszkiewicz } else { 3399895d8b56SArtur Paszkiewicz if (raid_bdev->bdev.blocklen != bdev->blocklen) { 3400895d8b56SArtur Paszkiewicz SPDK_ERRLOG("Raid bdev '%s' blocklen %u differs from base bdev '%s' blocklen %u\n", 3401895d8b56SArtur Paszkiewicz raid_bdev->bdev.name, raid_bdev->bdev.blocklen, bdev->name, bdev->blocklen); 3402895d8b56SArtur Paszkiewicz rc = -EINVAL; 3403895d8b56SArtur Paszkiewicz goto out; 3404895d8b56SArtur Paszkiewicz } 3405895d8b56SArtur Paszkiewicz 3406895d8b56SArtur Paszkiewicz if (raid_bdev->bdev.md_len != spdk_bdev_get_md_size(bdev) || 3407192db8deSSlawomir Ptak raid_bdev->bdev.md_interleave != spdk_bdev_is_md_interleaved(bdev) || 3408192db8deSSlawomir Ptak raid_bdev->bdev.dif_type != spdk_bdev_get_dif_type(bdev) || 3409192db8deSSlawomir Ptak raid_bdev->bdev.dif_check_flags != bdev->dif_check_flags || 3410fcf59a6fSShuhei Matsumoto raid_bdev->bdev.dif_is_head_of_md != spdk_bdev_is_dif_head_of_md(bdev) || 3411fcf59a6fSShuhei Matsumoto raid_bdev->bdev.dif_pi_format != bdev->dif_pi_format) { 3412895d8b56SArtur Paszkiewicz SPDK_ERRLOG("Raid bdev '%s' has different metadata format than base bdev '%s'\n", 3413895d8b56SArtur Paszkiewicz raid_bdev->bdev.name, bdev->name); 3414895d8b56SArtur Paszkiewicz rc = -EINVAL; 3415895d8b56SArtur Paszkiewicz goto out; 3416895d8b56SArtur Paszkiewicz } 3417895d8b56SArtur Paszkiewicz } 3418895d8b56SArtur Paszkiewicz 3419fc2398dfSArtur Paszkiewicz assert(base_info->configure_cb == NULL); 3420887b8ec4SArtur Paszkiewicz base_info->configure_cb = cb_fn; 3421887b8ec4SArtur Paszkiewicz base_info->configure_cb_ctx = cb_ctx; 3422887b8ec4SArtur Paszkiewicz 34239222ff97SArtur Paszkiewicz if (existing) { 34249222ff97SArtur Paszkiewicz raid_bdev_configure_base_bdev_cont(base_info); 34259222ff97SArtur Paszkiewicz } else { 34269222ff97SArtur Paszkiewicz /* check for existing superblock when using a new bdev */ 34279222ff97SArtur Paszkiewicz rc = raid_bdev_load_base_bdev_superblock(desc, base_info->app_thread_ch, 34289222ff97SArtur Paszkiewicz raid_bdev_configure_base_bdev_check_sb_cb, base_info); 34299222ff97SArtur Paszkiewicz if (rc) { 34309222ff97SArtur Paszkiewicz SPDK_ERRLOG("Failed to read bdev %s superblock: %s\n", 34319222ff97SArtur Paszkiewicz bdev->name, spdk_strerror(-rc)); 34328a6bb6a8SArtur Paszkiewicz } 34338a6bb6a8SArtur Paszkiewicz } 34348a6bb6a8SArtur Paszkiewicz out: 34358a6bb6a8SArtur Paszkiewicz if (rc != 0) { 3436fc2398dfSArtur Paszkiewicz base_info->configure_cb = NULL; 34378a6bb6a8SArtur Paszkiewicz raid_bdev_free_base_bdev_resource(base_info); 34388a6bb6a8SArtur Paszkiewicz } 343907fe6a43SSeth Howell return rc; 344007fe6a43SSeth Howell } 344107fe6a43SSeth Howell 3442887b8ec4SArtur Paszkiewicz int 3443e9af23deSArtur Paszkiewicz raid_bdev_add_base_bdev(struct raid_bdev *raid_bdev, const char *name, 3444887b8ec4SArtur Paszkiewicz raid_base_bdev_cb cb_fn, void *cb_ctx) 3445887b8ec4SArtur Paszkiewicz { 3446887b8ec4SArtur Paszkiewicz struct raid_base_bdev_info *base_info = NULL, *iter; 3447887b8ec4SArtur Paszkiewicz int rc; 3448887b8ec4SArtur Paszkiewicz 3449e9af23deSArtur Paszkiewicz assert(name != NULL); 3450887b8ec4SArtur Paszkiewicz assert(spdk_get_thread() == spdk_thread_get_app_thread()); 3451887b8ec4SArtur Paszkiewicz 3452574d258eSYankun Li if (raid_bdev->process != NULL) { 3453574d258eSYankun Li SPDK_ERRLOG("raid bdev '%s' is in process\n", 3454574d258eSYankun Li raid_bdev->bdev.name); 3455574d258eSYankun Li return -EPERM; 3456574d258eSYankun Li } 3457574d258eSYankun Li 34582a1b861bSArtur Paszkiewicz if (raid_bdev->state == RAID_BDEV_STATE_CONFIGURING) { 34592a1b861bSArtur Paszkiewicz struct spdk_bdev *bdev = spdk_bdev_get_by_name(name); 34602a1b861bSArtur Paszkiewicz 34612a1b861bSArtur Paszkiewicz if (bdev != NULL) { 3462887b8ec4SArtur Paszkiewicz RAID_FOR_EACH_BASE_BDEV(raid_bdev, iter) { 34632a1b861bSArtur Paszkiewicz if (iter->name == NULL && 34642a1b861bSArtur Paszkiewicz spdk_uuid_compare(&bdev->uuid, &iter->uuid) == 0) { 3465887b8ec4SArtur Paszkiewicz base_info = iter; 3466887b8ec4SArtur Paszkiewicz break; 3467887b8ec4SArtur Paszkiewicz } 3468887b8ec4SArtur Paszkiewicz } 34692a1b861bSArtur Paszkiewicz } 34702a1b861bSArtur Paszkiewicz } 34712a1b861bSArtur Paszkiewicz 34722a1b861bSArtur Paszkiewicz if (base_info == NULL || raid_bdev->state == RAID_BDEV_STATE_ONLINE) { 34732a1b861bSArtur Paszkiewicz RAID_FOR_EACH_BASE_BDEV(raid_bdev, iter) { 34742a1b861bSArtur Paszkiewicz if (iter->name == NULL && spdk_uuid_is_null(&iter->uuid)) { 34752a1b861bSArtur Paszkiewicz base_info = iter; 34762a1b861bSArtur Paszkiewicz break; 34772a1b861bSArtur Paszkiewicz } 34782a1b861bSArtur Paszkiewicz } 34792a1b861bSArtur Paszkiewicz } 3480887b8ec4SArtur Paszkiewicz 3481887b8ec4SArtur Paszkiewicz if (base_info == NULL) { 3482887b8ec4SArtur Paszkiewicz SPDK_ERRLOG("no empty slot found in raid bdev '%s' for new base bdev '%s'\n", 3483210c233fSArtur Paszkiewicz raid_bdev->bdev.name, name); 3484887b8ec4SArtur Paszkiewicz return -EINVAL; 3485887b8ec4SArtur Paszkiewicz } 3486887b8ec4SArtur Paszkiewicz 3487887b8ec4SArtur Paszkiewicz assert(base_info->is_configured == false); 34880074299dSArtur Paszkiewicz 34890074299dSArtur Paszkiewicz if (raid_bdev->state == RAID_BDEV_STATE_ONLINE) { 3490887b8ec4SArtur Paszkiewicz assert(base_info->data_size != 0); 34910074299dSArtur Paszkiewicz assert(base_info->desc == NULL); 34920074299dSArtur Paszkiewicz } 3493887b8ec4SArtur Paszkiewicz 3494e9af23deSArtur Paszkiewicz base_info->name = strdup(name); 3495e9af23deSArtur Paszkiewicz if (base_info->name == NULL) { 3496e9af23deSArtur Paszkiewicz return -ENOMEM; 3497e9af23deSArtur Paszkiewicz } 3498e9af23deSArtur Paszkiewicz 3499e9af23deSArtur Paszkiewicz rc = raid_bdev_configure_base_bdev(base_info, false, cb_fn, cb_ctx); 35000074299dSArtur Paszkiewicz if (rc != 0 && (rc != -ENODEV || raid_bdev->state != RAID_BDEV_STATE_CONFIGURING)) { 3501e9af23deSArtur Paszkiewicz SPDK_ERRLOG("base bdev '%s' configure failed: %s\n", name, spdk_strerror(-rc)); 3502e9af23deSArtur Paszkiewicz free(base_info->name); 3503e9af23deSArtur Paszkiewicz base_info->name = NULL; 3504887b8ec4SArtur Paszkiewicz } 3505887b8ec4SArtur Paszkiewicz 350607fe6a43SSeth Howell return rc; 350707fe6a43SSeth Howell } 350807fe6a43SSeth Howell 35098a6bb6a8SArtur Paszkiewicz static int 35108a6bb6a8SArtur Paszkiewicz raid_bdev_create_from_sb(const struct raid_bdev_superblock *sb, struct raid_bdev **raid_bdev_out) 35118a6bb6a8SArtur Paszkiewicz { 35128a6bb6a8SArtur Paszkiewicz struct raid_bdev *raid_bdev; 35138a6bb6a8SArtur Paszkiewicz uint8_t i; 35148a6bb6a8SArtur Paszkiewicz int rc; 35158a6bb6a8SArtur Paszkiewicz 3516255d0786SArtur Paszkiewicz rc = _raid_bdev_create(sb->name, (sb->strip_size * sb->block_size) / 1024, sb->num_base_bdevs, 35178a6bb6a8SArtur Paszkiewicz sb->level, true, &sb->uuid, &raid_bdev); 35188a6bb6a8SArtur Paszkiewicz if (rc != 0) { 35198a6bb6a8SArtur Paszkiewicz return rc; 35208a6bb6a8SArtur Paszkiewicz } 35218a6bb6a8SArtur Paszkiewicz 3522c25b80e2SArtur Paszkiewicz rc = raid_bdev_alloc_superblock(raid_bdev, sb->block_size); 3523c25b80e2SArtur Paszkiewicz if (rc != 0) { 3524c25b80e2SArtur Paszkiewicz raid_bdev_free(raid_bdev); 3525c25b80e2SArtur Paszkiewicz return rc; 3526c25b80e2SArtur Paszkiewicz } 3527c25b80e2SArtur Paszkiewicz 35288a6bb6a8SArtur Paszkiewicz assert(sb->length <= RAID_BDEV_SB_MAX_LENGTH); 35298a6bb6a8SArtur Paszkiewicz memcpy(raid_bdev->sb, sb, sb->length); 35308a6bb6a8SArtur Paszkiewicz 35318a6bb6a8SArtur Paszkiewicz for (i = 0; i < sb->base_bdevs_size; i++) { 35328a6bb6a8SArtur Paszkiewicz const struct raid_bdev_sb_base_bdev *sb_base_bdev = &sb->base_bdevs[i]; 35338a6bb6a8SArtur Paszkiewicz struct raid_base_bdev_info *base_info = &raid_bdev->base_bdev_info[sb_base_bdev->slot]; 35348a6bb6a8SArtur Paszkiewicz 35358a6bb6a8SArtur Paszkiewicz if (sb_base_bdev->state == RAID_SB_BASE_BDEV_CONFIGURED) { 35368a6bb6a8SArtur Paszkiewicz spdk_uuid_copy(&base_info->uuid, &sb_base_bdev->uuid); 3537255d0786SArtur Paszkiewicz raid_bdev->num_base_bdevs_operational++; 35388a6bb6a8SArtur Paszkiewicz } 35398a6bb6a8SArtur Paszkiewicz 35408a6bb6a8SArtur Paszkiewicz base_info->data_offset = sb_base_bdev->data_offset; 35418a6bb6a8SArtur Paszkiewicz base_info->data_size = sb_base_bdev->data_size; 35428a6bb6a8SArtur Paszkiewicz } 35438a6bb6a8SArtur Paszkiewicz 35448a6bb6a8SArtur Paszkiewicz *raid_bdev_out = raid_bdev; 35458a6bb6a8SArtur Paszkiewicz return 0; 35468a6bb6a8SArtur Paszkiewicz } 35478a6bb6a8SArtur Paszkiewicz 35488a6bb6a8SArtur Paszkiewicz static void 35498a6bb6a8SArtur Paszkiewicz raid_bdev_examine_no_sb(struct spdk_bdev *bdev) 35508a6bb6a8SArtur Paszkiewicz { 35518a6bb6a8SArtur Paszkiewicz struct raid_bdev *raid_bdev; 35528a6bb6a8SArtur Paszkiewicz struct raid_base_bdev_info *base_info; 35538a6bb6a8SArtur Paszkiewicz 35548a6bb6a8SArtur Paszkiewicz TAILQ_FOREACH(raid_bdev, &g_raid_bdev_list, global_link) { 35558aa7730cSArtur Paszkiewicz if (raid_bdev->state != RAID_BDEV_STATE_CONFIGURING || raid_bdev->sb != NULL) { 35568aa7730cSArtur Paszkiewicz continue; 35578aa7730cSArtur Paszkiewicz } 35588a6bb6a8SArtur Paszkiewicz RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) { 35592a1b861bSArtur Paszkiewicz if (base_info->desc == NULL && 35602a1b861bSArtur Paszkiewicz ((base_info->name != NULL && strcmp(bdev->name, base_info->name) == 0) || 35612a1b861bSArtur Paszkiewicz spdk_uuid_compare(&base_info->uuid, &bdev->uuid) == 0)) { 3562887b8ec4SArtur Paszkiewicz raid_bdev_configure_base_bdev(base_info, true, NULL, NULL); 35638a6bb6a8SArtur Paszkiewicz break; 35648a6bb6a8SArtur Paszkiewicz } 35658a6bb6a8SArtur Paszkiewicz } 35668a6bb6a8SArtur Paszkiewicz } 35678a6bb6a8SArtur Paszkiewicz } 35688a6bb6a8SArtur Paszkiewicz 3569f9cccaa8SArtur Paszkiewicz struct raid_bdev_examine_others_ctx { 3570f9cccaa8SArtur Paszkiewicz struct spdk_uuid raid_bdev_uuid; 3571f9cccaa8SArtur Paszkiewicz uint8_t current_base_bdev_idx; 3572f9cccaa8SArtur Paszkiewicz raid_base_bdev_cb cb_fn; 3573f9cccaa8SArtur Paszkiewicz void *cb_ctx; 3574f9cccaa8SArtur Paszkiewicz }; 3575f9cccaa8SArtur Paszkiewicz 3576f9cccaa8SArtur Paszkiewicz static void 3577f9cccaa8SArtur Paszkiewicz raid_bdev_examine_others_done(void *_ctx, int status) 3578f9cccaa8SArtur Paszkiewicz { 3579f9cccaa8SArtur Paszkiewicz struct raid_bdev_examine_others_ctx *ctx = _ctx; 3580f9cccaa8SArtur Paszkiewicz 3581f9cccaa8SArtur Paszkiewicz if (ctx->cb_fn != NULL) { 3582f9cccaa8SArtur Paszkiewicz ctx->cb_fn(ctx->cb_ctx, status); 3583f9cccaa8SArtur Paszkiewicz } 3584f9cccaa8SArtur Paszkiewicz free(ctx); 3585f9cccaa8SArtur Paszkiewicz } 3586f9cccaa8SArtur Paszkiewicz 3587f9cccaa8SArtur Paszkiewicz typedef void (*raid_bdev_examine_load_sb_cb)(struct spdk_bdev *bdev, 3588f9cccaa8SArtur Paszkiewicz const struct raid_bdev_superblock *sb, int status, void *ctx); 3589f9cccaa8SArtur Paszkiewicz static int raid_bdev_examine_load_sb(const char *bdev_name, raid_bdev_examine_load_sb_cb cb, 3590f9cccaa8SArtur Paszkiewicz void *cb_ctx); 3591f9cccaa8SArtur Paszkiewicz static void raid_bdev_examine_sb(const struct raid_bdev_superblock *sb, struct spdk_bdev *bdev, 3592f9cccaa8SArtur Paszkiewicz raid_base_bdev_cb cb_fn, void *cb_ctx); 3593f9cccaa8SArtur Paszkiewicz static void raid_bdev_examine_others(void *_ctx, int status); 3594f9cccaa8SArtur Paszkiewicz 3595f9cccaa8SArtur Paszkiewicz static void 3596f9cccaa8SArtur Paszkiewicz raid_bdev_examine_others_load_cb(struct spdk_bdev *bdev, const struct raid_bdev_superblock *sb, 3597f9cccaa8SArtur Paszkiewicz int status, void *_ctx) 3598f9cccaa8SArtur Paszkiewicz { 3599f9cccaa8SArtur Paszkiewicz struct raid_bdev_examine_others_ctx *ctx = _ctx; 3600f9cccaa8SArtur Paszkiewicz 3601f9cccaa8SArtur Paszkiewicz if (status != 0) { 3602f9cccaa8SArtur Paszkiewicz raid_bdev_examine_others_done(ctx, status); 3603f9cccaa8SArtur Paszkiewicz return; 3604f9cccaa8SArtur Paszkiewicz } 3605f9cccaa8SArtur Paszkiewicz 3606f9cccaa8SArtur Paszkiewicz raid_bdev_examine_sb(sb, bdev, raid_bdev_examine_others, ctx); 3607f9cccaa8SArtur Paszkiewicz } 3608f9cccaa8SArtur Paszkiewicz 3609f9cccaa8SArtur Paszkiewicz static void 3610f9cccaa8SArtur Paszkiewicz raid_bdev_examine_others(void *_ctx, int status) 3611f9cccaa8SArtur Paszkiewicz { 3612f9cccaa8SArtur Paszkiewicz struct raid_bdev_examine_others_ctx *ctx = _ctx; 3613f9cccaa8SArtur Paszkiewicz struct raid_bdev *raid_bdev; 3614f9cccaa8SArtur Paszkiewicz struct raid_base_bdev_info *base_info; 3615f9cccaa8SArtur Paszkiewicz char uuid_str[SPDK_UUID_STRING_LEN]; 3616f9cccaa8SArtur Paszkiewicz 361719f5787cSArtur Paszkiewicz if (status != 0 && status != -EEXIST) { 3618f9cccaa8SArtur Paszkiewicz goto out; 3619f9cccaa8SArtur Paszkiewicz } 3620f9cccaa8SArtur Paszkiewicz 3621f9cccaa8SArtur Paszkiewicz raid_bdev = raid_bdev_find_by_uuid(&ctx->raid_bdev_uuid); 3622f9cccaa8SArtur Paszkiewicz if (raid_bdev == NULL) { 3623f9cccaa8SArtur Paszkiewicz status = -ENODEV; 3624f9cccaa8SArtur Paszkiewicz goto out; 3625f9cccaa8SArtur Paszkiewicz } 3626f9cccaa8SArtur Paszkiewicz 3627f9cccaa8SArtur Paszkiewicz for (base_info = &raid_bdev->base_bdev_info[ctx->current_base_bdev_idx]; 3628f9cccaa8SArtur Paszkiewicz base_info < &raid_bdev->base_bdev_info[raid_bdev->num_base_bdevs]; 3629f9cccaa8SArtur Paszkiewicz base_info++) { 3630f9cccaa8SArtur Paszkiewicz if (base_info->is_configured || spdk_uuid_is_null(&base_info->uuid)) { 3631f9cccaa8SArtur Paszkiewicz continue; 3632f9cccaa8SArtur Paszkiewicz } 3633f9cccaa8SArtur Paszkiewicz 3634f9cccaa8SArtur Paszkiewicz spdk_uuid_fmt_lower(uuid_str, sizeof(uuid_str), &base_info->uuid); 3635f9cccaa8SArtur Paszkiewicz 3636f9cccaa8SArtur Paszkiewicz if (spdk_bdev_get_by_name(uuid_str) == NULL) { 3637f9cccaa8SArtur Paszkiewicz continue; 3638f9cccaa8SArtur Paszkiewicz } 3639f9cccaa8SArtur Paszkiewicz 3640f9cccaa8SArtur Paszkiewicz ctx->current_base_bdev_idx = raid_bdev_base_bdev_slot(base_info); 3641f9cccaa8SArtur Paszkiewicz 3642f9cccaa8SArtur Paszkiewicz status = raid_bdev_examine_load_sb(uuid_str, raid_bdev_examine_others_load_cb, ctx); 3643f9cccaa8SArtur Paszkiewicz if (status != 0) { 3644f9cccaa8SArtur Paszkiewicz continue; 3645f9cccaa8SArtur Paszkiewicz } 3646f9cccaa8SArtur Paszkiewicz return; 3647f9cccaa8SArtur Paszkiewicz } 3648f9cccaa8SArtur Paszkiewicz out: 3649f9cccaa8SArtur Paszkiewicz raid_bdev_examine_others_done(ctx, status); 3650f9cccaa8SArtur Paszkiewicz } 3651f9cccaa8SArtur Paszkiewicz 36528a6bb6a8SArtur Paszkiewicz static void 3653b694ff86SArtur Paszkiewicz raid_bdev_examine_sb(const struct raid_bdev_superblock *sb, struct spdk_bdev *bdev, 3654b694ff86SArtur Paszkiewicz raid_base_bdev_cb cb_fn, void *cb_ctx) 36558a6bb6a8SArtur Paszkiewicz { 36563bec6cb2SMichal Berger const struct raid_bdev_sb_base_bdev *sb_base_bdev = NULL; 36578a6bb6a8SArtur Paszkiewicz struct raid_bdev *raid_bdev; 36588a6bb6a8SArtur Paszkiewicz struct raid_base_bdev_info *iter, *base_info; 36598a6bb6a8SArtur Paszkiewicz uint8_t i; 36608a6bb6a8SArtur Paszkiewicz int rc; 36618a6bb6a8SArtur Paszkiewicz 3662bb374988SArtur Paszkiewicz if (sb->block_size != spdk_bdev_get_data_block_size(bdev)) { 36638a6bb6a8SArtur Paszkiewicz SPDK_WARNLOG("Bdev %s block size (%u) does not match the value in superblock (%u)\n", 3664bb374988SArtur Paszkiewicz bdev->name, sb->block_size, spdk_bdev_get_data_block_size(bdev)); 3665b694ff86SArtur Paszkiewicz rc = -EINVAL; 3666b694ff86SArtur Paszkiewicz goto out; 36678a6bb6a8SArtur Paszkiewicz } 36688a6bb6a8SArtur Paszkiewicz 36698a6bb6a8SArtur Paszkiewicz if (spdk_uuid_is_null(&sb->uuid)) { 36708a6bb6a8SArtur Paszkiewicz SPDK_WARNLOG("NULL raid bdev UUID in superblock on bdev %s\n", bdev->name); 3671b694ff86SArtur Paszkiewicz rc = -EINVAL; 3672b694ff86SArtur Paszkiewicz goto out; 36738a6bb6a8SArtur Paszkiewicz } 36748a6bb6a8SArtur Paszkiewicz 3675688de1b9SArtur Paszkiewicz raid_bdev = raid_bdev_find_by_uuid(&sb->uuid); 36768a6bb6a8SArtur Paszkiewicz 36778a6bb6a8SArtur Paszkiewicz if (raid_bdev) { 3678*fa3ab738SYankun Li if (raid_bdev->sb == NULL) { 3679*fa3ab738SYankun Li SPDK_WARNLOG("raid superblock is null\n"); 3680*fa3ab738SYankun Li rc = -EINVAL; 3681*fa3ab738SYankun Li goto out; 3682*fa3ab738SYankun Li } 3683*fa3ab738SYankun Li 36848a6bb6a8SArtur Paszkiewicz if (sb->seq_number > raid_bdev->sb->seq_number) { 36858a6bb6a8SArtur Paszkiewicz SPDK_DEBUGLOG(bdev_raid, 36868a6bb6a8SArtur Paszkiewicz "raid superblock seq_number on bdev %s (%lu) greater than existing raid bdev %s (%lu)\n", 36878a6bb6a8SArtur Paszkiewicz bdev->name, sb->seq_number, raid_bdev->bdev.name, raid_bdev->sb->seq_number); 36888a6bb6a8SArtur Paszkiewicz 36898a6bb6a8SArtur Paszkiewicz if (raid_bdev->state != RAID_BDEV_STATE_CONFIGURING) { 36908a6bb6a8SArtur Paszkiewicz SPDK_WARNLOG("Newer version of raid bdev %s superblock found on bdev %s but raid bdev is not in configuring state.\n", 36918a6bb6a8SArtur Paszkiewicz raid_bdev->bdev.name, bdev->name); 3692b694ff86SArtur Paszkiewicz rc = -EBUSY; 3693b694ff86SArtur Paszkiewicz goto out; 36948a6bb6a8SArtur Paszkiewicz } 36958a6bb6a8SArtur Paszkiewicz 36968a6bb6a8SArtur Paszkiewicz /* remove and then recreate the raid bdev using the newer superblock */ 36978a6bb6a8SArtur Paszkiewicz raid_bdev_delete(raid_bdev, NULL, NULL); 36988a6bb6a8SArtur Paszkiewicz raid_bdev = NULL; 36998a6bb6a8SArtur Paszkiewicz } else if (sb->seq_number < raid_bdev->sb->seq_number) { 37008a6bb6a8SArtur Paszkiewicz SPDK_DEBUGLOG(bdev_raid, 37018a6bb6a8SArtur Paszkiewicz "raid superblock seq_number on bdev %s (%lu) smaller than existing raid bdev %s (%lu)\n", 37028a6bb6a8SArtur Paszkiewicz bdev->name, sb->seq_number, raid_bdev->bdev.name, raid_bdev->sb->seq_number); 37038a6bb6a8SArtur Paszkiewicz /* use the current raid bdev superblock */ 37048a6bb6a8SArtur Paszkiewicz sb = raid_bdev->sb; 37058a6bb6a8SArtur Paszkiewicz } 37068a6bb6a8SArtur Paszkiewicz } 37078a6bb6a8SArtur Paszkiewicz 37088a6bb6a8SArtur Paszkiewicz for (i = 0; i < sb->base_bdevs_size; i++) { 37098a6bb6a8SArtur Paszkiewicz sb_base_bdev = &sb->base_bdevs[i]; 37108a6bb6a8SArtur Paszkiewicz 37118a6bb6a8SArtur Paszkiewicz assert(spdk_uuid_is_null(&sb_base_bdev->uuid) == false); 37128a6bb6a8SArtur Paszkiewicz 37138a6bb6a8SArtur Paszkiewicz if (spdk_uuid_compare(&sb_base_bdev->uuid, spdk_bdev_get_uuid(bdev)) == 0) { 37148a6bb6a8SArtur Paszkiewicz break; 37158a6bb6a8SArtur Paszkiewicz } 37168a6bb6a8SArtur Paszkiewicz } 37178a6bb6a8SArtur Paszkiewicz 37188a6bb6a8SArtur Paszkiewicz if (i == sb->base_bdevs_size) { 37198a6bb6a8SArtur Paszkiewicz SPDK_DEBUGLOG(bdev_raid, "raid superblock does not contain this bdev's uuid\n"); 3720b694ff86SArtur Paszkiewicz rc = -EINVAL; 3721b694ff86SArtur Paszkiewicz goto out; 37228a6bb6a8SArtur Paszkiewicz } 37238a6bb6a8SArtur Paszkiewicz 37248a6bb6a8SArtur Paszkiewicz if (!raid_bdev) { 3725f9cccaa8SArtur Paszkiewicz struct raid_bdev_examine_others_ctx *ctx; 3726f9cccaa8SArtur Paszkiewicz 3727f9cccaa8SArtur Paszkiewicz ctx = calloc(1, sizeof(*ctx)); 3728f9cccaa8SArtur Paszkiewicz if (ctx == NULL) { 3729f9cccaa8SArtur Paszkiewicz rc = -ENOMEM; 3730f9cccaa8SArtur Paszkiewicz goto out; 3731f9cccaa8SArtur Paszkiewicz } 3732f9cccaa8SArtur Paszkiewicz 37338a6bb6a8SArtur Paszkiewicz rc = raid_bdev_create_from_sb(sb, &raid_bdev); 37348a6bb6a8SArtur Paszkiewicz if (rc != 0) { 37358a6bb6a8SArtur Paszkiewicz SPDK_ERRLOG("Failed to create raid bdev %s: %s\n", 37368a6bb6a8SArtur Paszkiewicz sb->name, spdk_strerror(-rc)); 3737f9cccaa8SArtur Paszkiewicz free(ctx); 3738b694ff86SArtur Paszkiewicz goto out; 37398a6bb6a8SArtur Paszkiewicz } 3740f9cccaa8SArtur Paszkiewicz 3741f9cccaa8SArtur Paszkiewicz /* after this base bdev is configured, examine other base bdevs that may be present */ 3742f9cccaa8SArtur Paszkiewicz spdk_uuid_copy(&ctx->raid_bdev_uuid, &sb->uuid); 3743f9cccaa8SArtur Paszkiewicz ctx->cb_fn = cb_fn; 3744f9cccaa8SArtur Paszkiewicz ctx->cb_ctx = cb_ctx; 3745f9cccaa8SArtur Paszkiewicz 3746f9cccaa8SArtur Paszkiewicz cb_fn = raid_bdev_examine_others; 3747f9cccaa8SArtur Paszkiewicz cb_ctx = ctx; 37488a6bb6a8SArtur Paszkiewicz } 37498a6bb6a8SArtur Paszkiewicz 3750dafdb289SArtur Paszkiewicz if (raid_bdev->state == RAID_BDEV_STATE_ONLINE) { 3751dafdb289SArtur Paszkiewicz assert(sb_base_bdev->slot < raid_bdev->num_base_bdevs); 3752dafdb289SArtur Paszkiewicz base_info = &raid_bdev->base_bdev_info[sb_base_bdev->slot]; 37536518a98dSArtur Paszkiewicz assert(base_info->is_configured == false); 3754dafdb289SArtur Paszkiewicz assert(sb_base_bdev->state == RAID_SB_BASE_BDEV_MISSING || 3755dafdb289SArtur Paszkiewicz sb_base_bdev->state == RAID_SB_BASE_BDEV_FAILED); 3756dafdb289SArtur Paszkiewicz assert(spdk_uuid_is_null(&base_info->uuid)); 3757dafdb289SArtur Paszkiewicz spdk_uuid_copy(&base_info->uuid, &sb_base_bdev->uuid); 3758dafdb289SArtur Paszkiewicz SPDK_NOTICELOG("Re-adding bdev %s to raid bdev %s.\n", bdev->name, raid_bdev->bdev.name); 3759dafdb289SArtur Paszkiewicz rc = raid_bdev_configure_base_bdev(base_info, true, cb_fn, cb_ctx); 3760dafdb289SArtur Paszkiewicz if (rc != 0) { 3761dafdb289SArtur Paszkiewicz SPDK_ERRLOG("Failed to configure bdev %s as base bdev of raid %s: %s\n", 3762dafdb289SArtur Paszkiewicz bdev->name, raid_bdev->bdev.name, spdk_strerror(-rc)); 3763dafdb289SArtur Paszkiewicz } 3764dafdb289SArtur Paszkiewicz goto out; 3765dafdb289SArtur Paszkiewicz } 3766dafdb289SArtur Paszkiewicz 37678a6bb6a8SArtur Paszkiewicz if (sb_base_bdev->state != RAID_SB_BASE_BDEV_CONFIGURED) { 37688a6bb6a8SArtur Paszkiewicz SPDK_NOTICELOG("Bdev %s is not an active member of raid bdev %s. Ignoring.\n", 37698a6bb6a8SArtur Paszkiewicz bdev->name, raid_bdev->bdev.name); 3770b694ff86SArtur Paszkiewicz rc = -EINVAL; 3771b694ff86SArtur Paszkiewicz goto out; 37728a6bb6a8SArtur Paszkiewicz } 37738a6bb6a8SArtur Paszkiewicz 37748a6bb6a8SArtur Paszkiewicz base_info = NULL; 37758a6bb6a8SArtur Paszkiewicz RAID_FOR_EACH_BASE_BDEV(raid_bdev, iter) { 37768a6bb6a8SArtur Paszkiewicz if (spdk_uuid_compare(&iter->uuid, spdk_bdev_get_uuid(bdev)) == 0) { 37778a6bb6a8SArtur Paszkiewicz base_info = iter; 37788a6bb6a8SArtur Paszkiewicz break; 37798a6bb6a8SArtur Paszkiewicz } 37808a6bb6a8SArtur Paszkiewicz } 37818a6bb6a8SArtur Paszkiewicz 37828a6bb6a8SArtur Paszkiewicz if (base_info == NULL) { 37838a6bb6a8SArtur Paszkiewicz SPDK_ERRLOG("Bdev %s is not a member of raid bdev %s\n", 37848a6bb6a8SArtur Paszkiewicz bdev->name, raid_bdev->bdev.name); 3785b694ff86SArtur Paszkiewicz rc = -EINVAL; 3786b694ff86SArtur Paszkiewicz goto out; 37878a6bb6a8SArtur Paszkiewicz } 37888a6bb6a8SArtur Paszkiewicz 378919f5787cSArtur Paszkiewicz if (base_info->is_configured) { 379019f5787cSArtur Paszkiewicz rc = -EEXIST; 379119f5787cSArtur Paszkiewicz goto out; 379219f5787cSArtur Paszkiewicz } 379319f5787cSArtur Paszkiewicz 3794b694ff86SArtur Paszkiewicz rc = raid_bdev_configure_base_bdev(base_info, true, cb_fn, cb_ctx); 37958a6bb6a8SArtur Paszkiewicz if (rc != 0) { 37968a6bb6a8SArtur Paszkiewicz SPDK_ERRLOG("Failed to configure bdev %s as base bdev of raid %s: %s\n", 37978a6bb6a8SArtur Paszkiewicz bdev->name, raid_bdev->bdev.name, spdk_strerror(-rc)); 37988a6bb6a8SArtur Paszkiewicz } 3799b694ff86SArtur Paszkiewicz out: 3800b694ff86SArtur Paszkiewicz if (rc != 0 && cb_fn != 0) { 3801b694ff86SArtur Paszkiewicz cb_fn(cb_ctx, rc); 3802b694ff86SArtur Paszkiewicz } 38038a6bb6a8SArtur Paszkiewicz } 38048a6bb6a8SArtur Paszkiewicz 38058a6bb6a8SArtur Paszkiewicz struct raid_bdev_examine_ctx { 38068a6bb6a8SArtur Paszkiewicz struct spdk_bdev_desc *desc; 38078a6bb6a8SArtur Paszkiewicz struct spdk_io_channel *ch; 3808d014bf93SArtur Paszkiewicz raid_bdev_examine_load_sb_cb cb; 3809d014bf93SArtur Paszkiewicz void *cb_ctx; 38108a6bb6a8SArtur Paszkiewicz }; 38118a6bb6a8SArtur Paszkiewicz 38128a6bb6a8SArtur Paszkiewicz static void 38138a6bb6a8SArtur Paszkiewicz raid_bdev_examine_ctx_free(struct raid_bdev_examine_ctx *ctx) 38148a6bb6a8SArtur Paszkiewicz { 38158a6bb6a8SArtur Paszkiewicz if (!ctx) { 38168a6bb6a8SArtur Paszkiewicz return; 38178a6bb6a8SArtur Paszkiewicz } 38188a6bb6a8SArtur Paszkiewicz 38198a6bb6a8SArtur Paszkiewicz if (ctx->ch) { 38208a6bb6a8SArtur Paszkiewicz spdk_put_io_channel(ctx->ch); 38218a6bb6a8SArtur Paszkiewicz } 38228a6bb6a8SArtur Paszkiewicz 38238a6bb6a8SArtur Paszkiewicz if (ctx->desc) { 38248a6bb6a8SArtur Paszkiewicz spdk_bdev_close(ctx->desc); 38258a6bb6a8SArtur Paszkiewicz } 38268a6bb6a8SArtur Paszkiewicz 38278a6bb6a8SArtur Paszkiewicz free(ctx); 38288a6bb6a8SArtur Paszkiewicz } 38298a6bb6a8SArtur Paszkiewicz 38308a6bb6a8SArtur Paszkiewicz static void 3831d014bf93SArtur Paszkiewicz raid_bdev_examine_load_sb_done(const struct raid_bdev_superblock *sb, int status, void *_ctx) 38328a6bb6a8SArtur Paszkiewicz { 38338a6bb6a8SArtur Paszkiewicz struct raid_bdev_examine_ctx *ctx = _ctx; 38348a6bb6a8SArtur Paszkiewicz struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(ctx->desc); 38358a6bb6a8SArtur Paszkiewicz 3836d014bf93SArtur Paszkiewicz ctx->cb(bdev, sb, status, ctx->cb_ctx); 3837d014bf93SArtur Paszkiewicz 3838d014bf93SArtur Paszkiewicz raid_bdev_examine_ctx_free(ctx); 3839d014bf93SArtur Paszkiewicz } 3840d014bf93SArtur Paszkiewicz 3841d014bf93SArtur Paszkiewicz static void 3842d014bf93SArtur Paszkiewicz raid_bdev_examine_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *event_ctx) 3843d014bf93SArtur Paszkiewicz { 3844d014bf93SArtur Paszkiewicz } 3845d014bf93SArtur Paszkiewicz 3846d014bf93SArtur Paszkiewicz static int 3847d014bf93SArtur Paszkiewicz raid_bdev_examine_load_sb(const char *bdev_name, raid_bdev_examine_load_sb_cb cb, void *cb_ctx) 3848d014bf93SArtur Paszkiewicz { 3849d014bf93SArtur Paszkiewicz struct raid_bdev_examine_ctx *ctx; 3850d014bf93SArtur Paszkiewicz int rc; 3851d014bf93SArtur Paszkiewicz 3852d014bf93SArtur Paszkiewicz assert(cb != NULL); 3853d014bf93SArtur Paszkiewicz 3854d014bf93SArtur Paszkiewicz ctx = calloc(1, sizeof(*ctx)); 3855d014bf93SArtur Paszkiewicz if (!ctx) { 3856d014bf93SArtur Paszkiewicz return -ENOMEM; 3857d014bf93SArtur Paszkiewicz } 3858d014bf93SArtur Paszkiewicz 3859d014bf93SArtur Paszkiewicz rc = spdk_bdev_open_ext(bdev_name, false, raid_bdev_examine_event_cb, NULL, &ctx->desc); 3860d014bf93SArtur Paszkiewicz if (rc) { 3861d014bf93SArtur Paszkiewicz SPDK_ERRLOG("Failed to open bdev %s: %s\n", bdev_name, spdk_strerror(-rc)); 3862d014bf93SArtur Paszkiewicz goto err; 3863d014bf93SArtur Paszkiewicz } 3864d014bf93SArtur Paszkiewicz 3865d014bf93SArtur Paszkiewicz ctx->ch = spdk_bdev_get_io_channel(ctx->desc); 3866d014bf93SArtur Paszkiewicz if (!ctx->ch) { 3867d014bf93SArtur Paszkiewicz SPDK_ERRLOG("Failed to get io channel for bdev %s\n", bdev_name); 3868d014bf93SArtur Paszkiewicz rc = -ENOMEM; 3869d014bf93SArtur Paszkiewicz goto err; 3870d014bf93SArtur Paszkiewicz } 3871d014bf93SArtur Paszkiewicz 3872d014bf93SArtur Paszkiewicz ctx->cb = cb; 3873d014bf93SArtur Paszkiewicz ctx->cb_ctx = cb_ctx; 3874d014bf93SArtur Paszkiewicz 3875d014bf93SArtur Paszkiewicz rc = raid_bdev_load_base_bdev_superblock(ctx->desc, ctx->ch, raid_bdev_examine_load_sb_done, ctx); 3876d014bf93SArtur Paszkiewicz if (rc) { 3877d014bf93SArtur Paszkiewicz SPDK_ERRLOG("Failed to read bdev %s superblock: %s\n", 3878d014bf93SArtur Paszkiewicz bdev_name, spdk_strerror(-rc)); 3879d014bf93SArtur Paszkiewicz goto err; 3880d014bf93SArtur Paszkiewicz } 3881d014bf93SArtur Paszkiewicz 3882d014bf93SArtur Paszkiewicz return 0; 3883d014bf93SArtur Paszkiewicz err: 3884d014bf93SArtur Paszkiewicz raid_bdev_examine_ctx_free(ctx); 3885d014bf93SArtur Paszkiewicz return rc; 3886d014bf93SArtur Paszkiewicz } 3887d014bf93SArtur Paszkiewicz 3888d014bf93SArtur Paszkiewicz static void 3889bbccfa09SArtur Paszkiewicz raid_bdev_examine_done(void *ctx, int status) 3890bbccfa09SArtur Paszkiewicz { 3891bbccfa09SArtur Paszkiewicz struct spdk_bdev *bdev = ctx; 3892bbccfa09SArtur Paszkiewicz 3893bbccfa09SArtur Paszkiewicz if (status != 0) { 3894bbccfa09SArtur Paszkiewicz SPDK_ERRLOG("Failed to examine bdev %s: %s\n", 3895bbccfa09SArtur Paszkiewicz bdev->name, spdk_strerror(-status)); 3896bbccfa09SArtur Paszkiewicz } 3897bbccfa09SArtur Paszkiewicz spdk_bdev_module_examine_done(&g_raid_if); 3898bbccfa09SArtur Paszkiewicz } 3899bbccfa09SArtur Paszkiewicz 3900bbccfa09SArtur Paszkiewicz static void 3901d014bf93SArtur Paszkiewicz raid_bdev_examine_cont(struct spdk_bdev *bdev, const struct raid_bdev_superblock *sb, int status, 3902d014bf93SArtur Paszkiewicz void *ctx) 3903d014bf93SArtur Paszkiewicz { 39048a6bb6a8SArtur Paszkiewicz switch (status) { 39058a6bb6a8SArtur Paszkiewicz case 0: 39068a6bb6a8SArtur Paszkiewicz /* valid superblock found */ 39078a6bb6a8SArtur Paszkiewicz SPDK_DEBUGLOG(bdev_raid, "raid superblock found on bdev %s\n", bdev->name); 3908a5cd4a6dSArtur Paszkiewicz raid_bdev_examine_sb(sb, bdev, raid_bdev_examine_done, bdev); 3909a5cd4a6dSArtur Paszkiewicz return; 39108a6bb6a8SArtur Paszkiewicz case -EINVAL: 39118a6bb6a8SArtur Paszkiewicz /* no valid superblock, check if it can be claimed anyway */ 39128a6bb6a8SArtur Paszkiewicz raid_bdev_examine_no_sb(bdev); 3913bbccfa09SArtur Paszkiewicz status = 0; 39148a6bb6a8SArtur Paszkiewicz break; 39158a6bb6a8SArtur Paszkiewicz } 39168a6bb6a8SArtur Paszkiewicz 3917bbccfa09SArtur Paszkiewicz raid_bdev_examine_done(bdev, status); 39188a6bb6a8SArtur Paszkiewicz } 39198a6bb6a8SArtur Paszkiewicz 392007fe6a43SSeth Howell /* 392107fe6a43SSeth Howell * brief: 392207fe6a43SSeth Howell * raid_bdev_examine function is the examine function call by the below layers 392307fe6a43SSeth Howell * like bdev_nvme layer. This function will check if this base bdev can be 392407fe6a43SSeth Howell * claimed by this raid bdev or not. 392507fe6a43SSeth Howell * params: 392607fe6a43SSeth Howell * bdev - pointer to base bdev 392707fe6a43SSeth Howell * returns: 392807fe6a43SSeth Howell * none 392907fe6a43SSeth Howell */ 393007fe6a43SSeth Howell static void 393107fe6a43SSeth Howell raid_bdev_examine(struct spdk_bdev *bdev) 393207fe6a43SSeth Howell { 3933bbccfa09SArtur Paszkiewicz int rc = 0; 393407fe6a43SSeth Howell 3935ef282937SArtur Paszkiewicz if (raid_bdev_find_base_info_by_bdev(bdev) != NULL) { 3936ef282937SArtur Paszkiewicz goto done; 3937ef282937SArtur Paszkiewicz } 3938ef282937SArtur Paszkiewicz 3939796c1391SArtur Paszkiewicz if (spdk_bdev_get_dif_type(bdev) != SPDK_DIF_DISABLE) { 3940796c1391SArtur Paszkiewicz raid_bdev_examine_no_sb(bdev); 3941ef282937SArtur Paszkiewicz goto done; 3942796c1391SArtur Paszkiewicz } 3943796c1391SArtur Paszkiewicz 3944d014bf93SArtur Paszkiewicz rc = raid_bdev_examine_load_sb(bdev->name, raid_bdev_examine_cont, NULL); 3945d014bf93SArtur Paszkiewicz if (rc != 0) { 3946d014bf93SArtur Paszkiewicz goto done; 39478a6bb6a8SArtur Paszkiewicz } 39488a6bb6a8SArtur Paszkiewicz 39498a6bb6a8SArtur Paszkiewicz return; 3950ef282937SArtur Paszkiewicz done: 3951bbccfa09SArtur Paszkiewicz raid_bdev_examine_done(bdev, rc); 395207fe6a43SSeth Howell } 395307fe6a43SSeth Howell 395407fe6a43SSeth Howell /* Log component for bdev raid bdev module */ 39552172c432STomasz Zawadzki SPDK_LOG_REGISTER_COMPONENT(bdev_raid) 39568d52c4c2Sxupeng-mingtu 3957fbfc2c9dSKonrad Sztyber static void 3958fbfc2c9dSKonrad Sztyber bdev_raid_trace(void) 39598d52c4c2Sxupeng-mingtu { 39608d52c4c2Sxupeng-mingtu struct spdk_trace_tpoint_opts opts[] = { 39618d52c4c2Sxupeng-mingtu { 39628d52c4c2Sxupeng-mingtu "BDEV_RAID_IO_START", TRACE_BDEV_RAID_IO_START, 39638d52c4c2Sxupeng-mingtu OWNER_TYPE_NONE, OBJECT_BDEV_RAID_IO, 1, 39648d52c4c2Sxupeng-mingtu {{ "ctx", SPDK_TRACE_ARG_TYPE_PTR, 8 }} 39658d52c4c2Sxupeng-mingtu }, 39668d52c4c2Sxupeng-mingtu { 39678d52c4c2Sxupeng-mingtu "BDEV_RAID_IO_DONE", TRACE_BDEV_RAID_IO_DONE, 39688d52c4c2Sxupeng-mingtu OWNER_TYPE_NONE, OBJECT_BDEV_RAID_IO, 0, 39698d52c4c2Sxupeng-mingtu {{ "ctx", SPDK_TRACE_ARG_TYPE_PTR, 8 }} 39708d52c4c2Sxupeng-mingtu } 39718d52c4c2Sxupeng-mingtu }; 39728d52c4c2Sxupeng-mingtu 39738d52c4c2Sxupeng-mingtu 39748d52c4c2Sxupeng-mingtu spdk_trace_register_object(OBJECT_BDEV_RAID_IO, 'R'); 39758d52c4c2Sxupeng-mingtu spdk_trace_register_description_ext(opts, SPDK_COUNTOF(opts)); 39768d52c4c2Sxupeng-mingtu spdk_trace_tpoint_register_relation(TRACE_BDEV_IO_START, OBJECT_BDEV_RAID_IO, 1); 39778d52c4c2Sxupeng-mingtu spdk_trace_tpoint_register_relation(TRACE_BDEV_IO_DONE, OBJECT_BDEV_RAID_IO, 0); 39788d52c4c2Sxupeng-mingtu } 3979fbfc2c9dSKonrad Sztyber SPDK_TRACE_REGISTER_FN(bdev_raid_trace, "bdev_raid", TRACE_GROUP_BDEV_RAID) 3980