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" 1407fe6a43SSeth Howell 1507fe6a43SSeth Howell static bool g_shutdown_started = false; 1607fe6a43SSeth Howell 1707fe6a43SSeth Howell /* List of all raid bdevs */ 1807fe6a43SSeth Howell struct raid_all_tailq g_raid_bdev_list = TAILQ_HEAD_INITIALIZER(g_raid_bdev_list); 1907fe6a43SSeth Howell 20706029d5SArtur Paszkiewicz static TAILQ_HEAD(, raid_bdev_module) g_raid_modules = TAILQ_HEAD_INITIALIZER(g_raid_modules); 21706029d5SArtur Paszkiewicz 228dd1cd21SBen Walker static struct raid_bdev_module * 238dd1cd21SBen Walker raid_bdev_module_find(enum raid_level level) 24706029d5SArtur Paszkiewicz { 25706029d5SArtur Paszkiewicz struct raid_bdev_module *raid_module; 26706029d5SArtur Paszkiewicz 27706029d5SArtur Paszkiewicz TAILQ_FOREACH(raid_module, &g_raid_modules, link) { 28706029d5SArtur Paszkiewicz if (raid_module->level == level) { 29706029d5SArtur Paszkiewicz return raid_module; 30706029d5SArtur Paszkiewicz } 31706029d5SArtur Paszkiewicz } 32706029d5SArtur Paszkiewicz 33706029d5SArtur Paszkiewicz return NULL; 34706029d5SArtur Paszkiewicz } 35706029d5SArtur Paszkiewicz 368dd1cd21SBen Walker void 378dd1cd21SBen Walker raid_bdev_module_list_add(struct raid_bdev_module *raid_module) 38706029d5SArtur Paszkiewicz { 39706029d5SArtur Paszkiewicz if (raid_bdev_module_find(raid_module->level) != NULL) { 40706029d5SArtur Paszkiewicz SPDK_ERRLOG("module for raid level '%s' already registered.\n", 41706029d5SArtur Paszkiewicz raid_bdev_level_to_str(raid_module->level)); 42706029d5SArtur Paszkiewicz assert(false); 43706029d5SArtur Paszkiewicz } else { 44706029d5SArtur Paszkiewicz TAILQ_INSERT_TAIL(&g_raid_modules, raid_module, link); 45706029d5SArtur Paszkiewicz } 46706029d5SArtur Paszkiewicz } 47706029d5SArtur Paszkiewicz 4807fe6a43SSeth Howell /* Function declarations */ 4907fe6a43SSeth Howell static void raid_bdev_examine(struct spdk_bdev *bdev); 5007fe6a43SSeth Howell static int raid_bdev_init(void); 5107fe6a43SSeth Howell static void raid_bdev_deconfigure(struct raid_bdev *raid_bdev, 5207fe6a43SSeth Howell raid_bdev_destruct_cb cb_fn, void *cb_arg); 5307fe6a43SSeth Howell 5407fe6a43SSeth Howell /* 5507fe6a43SSeth Howell * brief: 5607fe6a43SSeth Howell * raid_bdev_create_cb function is a cb function for raid bdev which creates the 5707fe6a43SSeth Howell * hierarchy from raid bdev to base bdev io channels. It will be called per core 5807fe6a43SSeth Howell * params: 5907fe6a43SSeth Howell * io_device - pointer to raid bdev io device represented by raid_bdev 6007fe6a43SSeth Howell * ctx_buf - pointer to context buffer for raid bdev io channel 6107fe6a43SSeth Howell * returns: 6207fe6a43SSeth Howell * 0 - success 6307fe6a43SSeth Howell * non zero - failure 6407fe6a43SSeth Howell */ 6507fe6a43SSeth Howell static int 6607fe6a43SSeth Howell raid_bdev_create_cb(void *io_device, void *ctx_buf) 6707fe6a43SSeth Howell { 6807fe6a43SSeth Howell struct raid_bdev *raid_bdev = io_device; 6907fe6a43SSeth Howell struct raid_bdev_io_channel *raid_ch = ctx_buf; 709d94e1f5SArtur Paszkiewicz uint8_t i; 71c89e2008SArtur Paszkiewicz int ret = 0; 7207fe6a43SSeth Howell 732172c432STomasz Zawadzki SPDK_DEBUGLOG(bdev_raid, "raid_bdev_create_cb, %p\n", raid_ch); 7407fe6a43SSeth Howell 7507fe6a43SSeth Howell assert(raid_bdev != NULL); 7607fe6a43SSeth Howell assert(raid_bdev->state == RAID_BDEV_STATE_ONLINE); 7707fe6a43SSeth Howell 7807fe6a43SSeth Howell raid_ch->num_channels = raid_bdev->num_base_bdevs; 7907fe6a43SSeth Howell 8007fe6a43SSeth Howell raid_ch->base_channel = calloc(raid_ch->num_channels, 8107fe6a43SSeth Howell sizeof(struct spdk_io_channel *)); 8207fe6a43SSeth Howell if (!raid_ch->base_channel) { 8307fe6a43SSeth Howell SPDK_ERRLOG("Unable to allocate base bdevs io channel\n"); 8407fe6a43SSeth Howell return -ENOMEM; 8507fe6a43SSeth Howell } 86b42cb0e5SArtur Paszkiewicz 87b42cb0e5SArtur Paszkiewicz spdk_spin_lock(&raid_bdev->base_bdev_lock); 889d94e1f5SArtur Paszkiewicz for (i = 0; i < raid_ch->num_channels; i++) { 8907fe6a43SSeth Howell /* 9007fe6a43SSeth Howell * Get the spdk_io_channel for all the base bdevs. This is used during 9107fe6a43SSeth Howell * split logic to send the respective child bdev ios to respective base 9207fe6a43SSeth Howell * bdev io channel. 9307fe6a43SSeth Howell */ 94b42cb0e5SArtur Paszkiewicz if (raid_bdev->base_bdev_info[i].desc == NULL) { 95b42cb0e5SArtur Paszkiewicz continue; 96b42cb0e5SArtur Paszkiewicz } 9707fe6a43SSeth Howell raid_ch->base_channel[i] = spdk_bdev_get_io_channel( 9807fe6a43SSeth Howell raid_bdev->base_bdev_info[i].desc); 9907fe6a43SSeth Howell if (!raid_ch->base_channel[i]) { 100c89e2008SArtur Paszkiewicz SPDK_ERRLOG("Unable to create io channel for base bdev\n"); 101c89e2008SArtur Paszkiewicz ret = -ENOMEM; 102c89e2008SArtur Paszkiewicz break; 103c89e2008SArtur Paszkiewicz } 104c89e2008SArtur Paszkiewicz } 105b42cb0e5SArtur Paszkiewicz spdk_spin_unlock(&raid_bdev->base_bdev_lock); 106c89e2008SArtur Paszkiewicz 107c89e2008SArtur Paszkiewicz if (!ret && raid_bdev->module->get_io_channel) { 108c89e2008SArtur Paszkiewicz raid_ch->module_channel = raid_bdev->module->get_io_channel(raid_bdev); 109c89e2008SArtur Paszkiewicz if (!raid_ch->module_channel) { 110c89e2008SArtur Paszkiewicz SPDK_ERRLOG("Unable to create io channel for raid module\n"); 111c89e2008SArtur Paszkiewicz ret = -ENOMEM; 112c89e2008SArtur Paszkiewicz } 113c89e2008SArtur Paszkiewicz } 114c89e2008SArtur Paszkiewicz 115c89e2008SArtur Paszkiewicz if (ret) { 116b42cb0e5SArtur Paszkiewicz for (i = 0; i < raid_ch->num_channels; i++) { 117b42cb0e5SArtur Paszkiewicz if (raid_ch->base_channel[i] != NULL) { 118b42cb0e5SArtur Paszkiewicz spdk_put_io_channel(raid_ch->base_channel[i]); 119b42cb0e5SArtur Paszkiewicz } 12007fe6a43SSeth Howell } 12107fe6a43SSeth Howell free(raid_ch->base_channel); 12207fe6a43SSeth Howell raid_ch->base_channel = NULL; 12307fe6a43SSeth Howell } 124c89e2008SArtur Paszkiewicz return ret; 12507fe6a43SSeth Howell } 12607fe6a43SSeth Howell 12707fe6a43SSeth Howell /* 12807fe6a43SSeth Howell * brief: 12907fe6a43SSeth Howell * raid_bdev_destroy_cb function is a cb function for raid bdev which deletes the 13007fe6a43SSeth Howell * hierarchy from raid bdev to base bdev io channels. It will be called per core 13107fe6a43SSeth Howell * params: 13207fe6a43SSeth Howell * io_device - pointer to raid bdev io device represented by raid_bdev 13307fe6a43SSeth Howell * ctx_buf - pointer to context buffer for raid bdev io channel 13407fe6a43SSeth Howell * returns: 13507fe6a43SSeth Howell * none 13607fe6a43SSeth Howell */ 13707fe6a43SSeth Howell static void 13807fe6a43SSeth Howell raid_bdev_destroy_cb(void *io_device, void *ctx_buf) 13907fe6a43SSeth Howell { 14007fe6a43SSeth Howell struct raid_bdev_io_channel *raid_ch = ctx_buf; 1419d94e1f5SArtur Paszkiewicz uint8_t i; 14207fe6a43SSeth Howell 1432172c432STomasz Zawadzki SPDK_DEBUGLOG(bdev_raid, "raid_bdev_destroy_cb\n"); 14407fe6a43SSeth Howell 14507fe6a43SSeth Howell assert(raid_ch != NULL); 14607fe6a43SSeth Howell assert(raid_ch->base_channel); 147c89e2008SArtur Paszkiewicz 148c89e2008SArtur Paszkiewicz if (raid_ch->module_channel) { 149c89e2008SArtur Paszkiewicz spdk_put_io_channel(raid_ch->module_channel); 150c89e2008SArtur Paszkiewicz } 151c89e2008SArtur Paszkiewicz 1529d94e1f5SArtur Paszkiewicz for (i = 0; i < raid_ch->num_channels; i++) { 15307fe6a43SSeth Howell /* Free base bdev channels */ 154b42cb0e5SArtur Paszkiewicz if (raid_ch->base_channel[i] != NULL) { 15507fe6a43SSeth Howell spdk_put_io_channel(raid_ch->base_channel[i]); 15607fe6a43SSeth Howell } 157b42cb0e5SArtur Paszkiewicz } 15807fe6a43SSeth Howell free(raid_ch->base_channel); 15907fe6a43SSeth Howell raid_ch->base_channel = NULL; 16007fe6a43SSeth Howell } 16107fe6a43SSeth Howell 16207fe6a43SSeth Howell /* 16307fe6a43SSeth Howell * brief: 16495a04949SArtur Paszkiewicz * raid_bdev_cleanup is used to cleanup raid_bdev related data 16507fe6a43SSeth Howell * structures. 16607fe6a43SSeth Howell * params: 16707fe6a43SSeth Howell * raid_bdev - pointer to raid_bdev 16807fe6a43SSeth Howell * returns: 16907fe6a43SSeth Howell * none 17007fe6a43SSeth Howell */ 17107fe6a43SSeth Howell static void 17207fe6a43SSeth Howell raid_bdev_cleanup(struct raid_bdev *raid_bdev) 17307fe6a43SSeth Howell { 174dccdd1e5SArtur Paszkiewicz struct raid_base_bdev_info *base_info; 175dccdd1e5SArtur Paszkiewicz 17646ff15a6SArtur Paszkiewicz SPDK_DEBUGLOG(bdev_raid, "raid_bdev_cleanup, %p name %s, state %s\n", 17746ff15a6SArtur Paszkiewicz raid_bdev, raid_bdev->bdev.name, raid_bdev_state_to_str(raid_bdev->state)); 17812ed89acSArtur Paszkiewicz assert(raid_bdev->state != RAID_BDEV_STATE_ONLINE); 1794dd2a0d3SArtur Paszkiewicz assert(spdk_get_thread() == spdk_thread_get_app_thread()); 180dccdd1e5SArtur Paszkiewicz 181dccdd1e5SArtur Paszkiewicz RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) { 182dccdd1e5SArtur Paszkiewicz assert(base_info->desc == NULL); 183dccdd1e5SArtur Paszkiewicz free(base_info->name); 184dccdd1e5SArtur Paszkiewicz } 185dccdd1e5SArtur Paszkiewicz 18607fe6a43SSeth Howell TAILQ_REMOVE(&g_raid_bdev_list, raid_bdev, global_link); 18795a04949SArtur Paszkiewicz } 18895a04949SArtur Paszkiewicz 18995a04949SArtur Paszkiewicz static void 19095a04949SArtur Paszkiewicz raid_bdev_free(struct raid_bdev *raid_bdev) 19195a04949SArtur Paszkiewicz { 19277b8f7b6SArtur Paszkiewicz spdk_dma_free(raid_bdev->sb); 193b42cb0e5SArtur Paszkiewicz spdk_spin_destroy(&raid_bdev->base_bdev_lock); 194fbdb05f0SArtur Paszkiewicz free(raid_bdev->base_bdev_info); 19595a04949SArtur Paszkiewicz free(raid_bdev->bdev.name); 19607fe6a43SSeth Howell free(raid_bdev); 19707fe6a43SSeth Howell } 19807fe6a43SSeth Howell 19995a04949SArtur Paszkiewicz static void 20095a04949SArtur Paszkiewicz raid_bdev_cleanup_and_free(struct raid_bdev *raid_bdev) 20195a04949SArtur Paszkiewicz { 20295a04949SArtur Paszkiewicz raid_bdev_cleanup(raid_bdev); 20395a04949SArtur Paszkiewicz raid_bdev_free(raid_bdev); 20495a04949SArtur Paszkiewicz } 20595a04949SArtur Paszkiewicz 20607fe6a43SSeth Howell /* 20707fe6a43SSeth Howell * brief: 20807fe6a43SSeth Howell * free resource of base bdev for raid bdev 20907fe6a43SSeth Howell * params: 210a193dcb8SArtur Paszkiewicz * base_info - raid base bdev info 21107fe6a43SSeth Howell * returns: 21277b8f7b6SArtur Paszkiewicz * none 21307fe6a43SSeth Howell */ 21407fe6a43SSeth Howell static void 21526861b70SArtur Paszkiewicz raid_bdev_free_base_bdev_resource(struct raid_base_bdev_info *base_info) 21607fe6a43SSeth Howell { 21726861b70SArtur Paszkiewicz struct raid_bdev *raid_bdev = base_info->raid_bdev; 21826861b70SArtur Paszkiewicz 2194dd2a0d3SArtur Paszkiewicz assert(spdk_get_thread() == spdk_thread_get_app_thread()); 2204dd2a0d3SArtur Paszkiewicz 221dccdd1e5SArtur Paszkiewicz free(base_info->name); 222dccdd1e5SArtur Paszkiewicz base_info->name = NULL; 2238a6bb6a8SArtur Paszkiewicz if (raid_bdev->state != RAID_BDEV_STATE_CONFIGURING) { 2248a6bb6a8SArtur Paszkiewicz spdk_uuid_set_null(&base_info->uuid); 2258a6bb6a8SArtur Paszkiewicz } 226dccdd1e5SArtur Paszkiewicz 2278d1993a5SArtur Paszkiewicz if (base_info->desc == NULL) { 228dccdd1e5SArtur Paszkiewicz return; 229dccdd1e5SArtur Paszkiewicz } 230dccdd1e5SArtur Paszkiewicz 2318d1993a5SArtur Paszkiewicz spdk_bdev_module_release_bdev(spdk_bdev_desc_get_bdev(base_info->desc)); 232a193dcb8SArtur Paszkiewicz spdk_bdev_close(base_info->desc); 233a193dcb8SArtur Paszkiewicz base_info->desc = NULL; 23477b8f7b6SArtur Paszkiewicz spdk_put_io_channel(base_info->app_thread_ch); 23577b8f7b6SArtur Paszkiewicz base_info->app_thread_ch = NULL; 23607fe6a43SSeth Howell 2379222ff97SArtur Paszkiewicz if (base_info->is_configured) { 23807fe6a43SSeth Howell assert(raid_bdev->num_base_bdevs_discovered); 23907fe6a43SSeth Howell raid_bdev->num_base_bdevs_discovered--; 2409222ff97SArtur Paszkiewicz base_info->is_configured = false; 2419222ff97SArtur Paszkiewicz } 24207fe6a43SSeth Howell } 24307fe6a43SSeth Howell 24495a04949SArtur Paszkiewicz static void 24595a04949SArtur Paszkiewicz raid_bdev_io_device_unregister_cb(void *io_device) 24695a04949SArtur Paszkiewicz { 24795a04949SArtur Paszkiewicz struct raid_bdev *raid_bdev = io_device; 24895a04949SArtur Paszkiewicz 24995a04949SArtur Paszkiewicz if (raid_bdev->num_base_bdevs_discovered == 0) { 25095a04949SArtur Paszkiewicz /* Free raid_bdev when there are no base bdevs left */ 25195a04949SArtur Paszkiewicz SPDK_DEBUGLOG(bdev_raid, "raid bdev base bdevs is 0, going to free all in destruct\n"); 25295a04949SArtur Paszkiewicz raid_bdev_cleanup(raid_bdev); 25395a04949SArtur Paszkiewicz spdk_bdev_destruct_done(&raid_bdev->bdev, 0); 25495a04949SArtur Paszkiewicz raid_bdev_free(raid_bdev); 25595a04949SArtur Paszkiewicz } else { 25695a04949SArtur Paszkiewicz spdk_bdev_destruct_done(&raid_bdev->bdev, 0); 25795a04949SArtur Paszkiewicz } 25895a04949SArtur Paszkiewicz } 25995a04949SArtur Paszkiewicz 2609cf1ab5bSArtur Paszkiewicz void 2619cf1ab5bSArtur Paszkiewicz raid_bdev_module_stop_done(struct raid_bdev *raid_bdev) 2629cf1ab5bSArtur Paszkiewicz { 2639cf1ab5bSArtur Paszkiewicz if (raid_bdev->state != RAID_BDEV_STATE_CONFIGURING) { 2649cf1ab5bSArtur Paszkiewicz spdk_io_device_unregister(raid_bdev, raid_bdev_io_device_unregister_cb); 2659cf1ab5bSArtur Paszkiewicz } 2669cf1ab5bSArtur Paszkiewicz } 2679cf1ab5bSArtur Paszkiewicz 2684dd2a0d3SArtur Paszkiewicz static void 2694dd2a0d3SArtur Paszkiewicz _raid_bdev_destruct(void *ctxt) 27007fe6a43SSeth Howell { 27107fe6a43SSeth Howell struct raid_bdev *raid_bdev = ctxt; 272a193dcb8SArtur Paszkiewicz struct raid_base_bdev_info *base_info; 27307fe6a43SSeth Howell 2742172c432STomasz Zawadzki SPDK_DEBUGLOG(bdev_raid, "raid_bdev_destruct\n"); 27507fe6a43SSeth Howell 276a193dcb8SArtur Paszkiewicz RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) { 27707fe6a43SSeth Howell /* 27807fe6a43SSeth Howell * Close all base bdev descriptors for which call has come from below 27907fe6a43SSeth Howell * layers. Also close the descriptors if we have started shutdown. 28007fe6a43SSeth Howell */ 281dccdd1e5SArtur Paszkiewicz if (g_shutdown_started || base_info->remove_scheduled == true) { 28226861b70SArtur Paszkiewicz raid_bdev_free_base_bdev_resource(base_info); 28307fe6a43SSeth Howell } 28407fe6a43SSeth Howell } 28507fe6a43SSeth Howell 28607fe6a43SSeth Howell if (g_shutdown_started) { 28707fe6a43SSeth Howell raid_bdev->state = RAID_BDEV_STATE_OFFLINE; 28807fe6a43SSeth Howell } 28907fe6a43SSeth Howell 290df80e8ffSyupeng if (raid_bdev->module->stop != NULL) { 2919cf1ab5bSArtur Paszkiewicz if (raid_bdev->module->stop(raid_bdev) == false) { 2924dd2a0d3SArtur Paszkiewicz return; 2939cf1ab5bSArtur Paszkiewicz } 294df80e8ffSyupeng } 295df80e8ffSyupeng 2969cf1ab5bSArtur Paszkiewicz raid_bdev_module_stop_done(raid_bdev); 2974dd2a0d3SArtur Paszkiewicz } 2984dd2a0d3SArtur Paszkiewicz 2994dd2a0d3SArtur Paszkiewicz static int 3004dd2a0d3SArtur Paszkiewicz raid_bdev_destruct(void *ctx) 3014dd2a0d3SArtur Paszkiewicz { 3024dd2a0d3SArtur Paszkiewicz spdk_thread_exec_msg(spdk_thread_get_app_thread(), _raid_bdev_destruct, ctx); 30307fe6a43SSeth Howell 30495a04949SArtur Paszkiewicz return 1; 30507fe6a43SSeth Howell } 30607fe6a43SSeth Howell 3076ba11b19SArtur Paszkiewicz void 3086ba11b19SArtur Paszkiewicz raid_bdev_io_complete(struct raid_bdev_io *raid_io, enum spdk_bdev_io_status status) 3096ba11b19SArtur Paszkiewicz { 3106ba11b19SArtur Paszkiewicz struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(raid_io); 3116ba11b19SArtur Paszkiewicz 3126ba11b19SArtur Paszkiewicz spdk_bdev_io_complete(bdev_io, status); 3136ba11b19SArtur Paszkiewicz } 3146ba11b19SArtur Paszkiewicz 31507fe6a43SSeth Howell /* 31607fe6a43SSeth Howell * brief: 3172efe6d92SArtur Paszkiewicz * raid_bdev_io_complete_part - signal the completion of a part of the expected 3182efe6d92SArtur Paszkiewicz * base bdev IOs and complete the raid_io if this is the final expected IO. 3192efe6d92SArtur Paszkiewicz * The caller should first set raid_io->base_bdev_io_remaining. This function 3202efe6d92SArtur Paszkiewicz * will decrement this counter by the value of the 'completed' parameter and 3212efe6d92SArtur Paszkiewicz * complete the raid_io if the counter reaches 0. The caller is free to 3222efe6d92SArtur Paszkiewicz * interpret the 'base_bdev_io_remaining' and 'completed' values as needed, 3232efe6d92SArtur Paszkiewicz * it can represent e.g. blocks or IOs. 324a5d9d778Spaul luse * params: 3252efe6d92SArtur Paszkiewicz * raid_io - pointer to raid_bdev_io 3262efe6d92SArtur Paszkiewicz * completed - the part of the raid_io that has been completed 3272efe6d92SArtur Paszkiewicz * status - status of the base IO 328a5d9d778Spaul luse * returns: 3292efe6d92SArtur Paszkiewicz * true - if the raid_io is completed 3302efe6d92SArtur Paszkiewicz * false - otherwise 331a5d9d778Spaul luse */ 3322efe6d92SArtur Paszkiewicz bool 3332efe6d92SArtur Paszkiewicz raid_bdev_io_complete_part(struct raid_bdev_io *raid_io, uint64_t completed, 3342efe6d92SArtur Paszkiewicz enum spdk_bdev_io_status status) 335a5d9d778Spaul luse { 3362efe6d92SArtur Paszkiewicz assert(raid_io->base_bdev_io_remaining >= completed); 3372efe6d92SArtur Paszkiewicz raid_io->base_bdev_io_remaining -= completed; 338a5d9d778Spaul luse 3392efe6d92SArtur Paszkiewicz if (status != SPDK_BDEV_IO_STATUS_SUCCESS) { 3402efe6d92SArtur Paszkiewicz raid_io->base_bdev_io_status = status; 341a5d9d778Spaul luse } 342a5d9d778Spaul luse 3432efe6d92SArtur Paszkiewicz if (raid_io->base_bdev_io_remaining == 0) { 3446ba11b19SArtur Paszkiewicz raid_bdev_io_complete(raid_io, raid_io->base_bdev_io_status); 3452efe6d92SArtur Paszkiewicz return true; 3462efe6d92SArtur Paszkiewicz } else { 3472efe6d92SArtur Paszkiewicz return false; 348a5d9d778Spaul luse } 349a5d9d778Spaul luse } 350a5d9d778Spaul luse 35107fe6a43SSeth Howell /* 35207fe6a43SSeth Howell * brief: 3531d246e97SArtur Paszkiewicz * raid_bdev_queue_io_wait function processes the IO which failed to submit. 3541d246e97SArtur Paszkiewicz * It will try to queue the IOs after storing the context to bdev wait queue logic. 35507fe6a43SSeth Howell * params: 356ae70d6a4SArtur Paszkiewicz * raid_io - pointer to raid_bdev_io 357ae70d6a4SArtur Paszkiewicz * bdev - the block device that the IO is submitted to 358ae70d6a4SArtur Paszkiewicz * ch - io channel 359ae70d6a4SArtur Paszkiewicz * cb_fn - callback when the spdk_bdev_io for bdev becomes available 36007fe6a43SSeth Howell * returns: 36107fe6a43SSeth Howell * none 36207fe6a43SSeth Howell */ 363fc9ca1d0SArtur Paszkiewicz void 364ae70d6a4SArtur Paszkiewicz raid_bdev_queue_io_wait(struct raid_bdev_io *raid_io, struct spdk_bdev *bdev, 365ae70d6a4SArtur Paszkiewicz struct spdk_io_channel *ch, spdk_bdev_io_wait_cb cb_fn) 36607fe6a43SSeth Howell { 367ae70d6a4SArtur Paszkiewicz raid_io->waitq_entry.bdev = bdev; 36807fe6a43SSeth Howell raid_io->waitq_entry.cb_fn = cb_fn; 369ae70d6a4SArtur Paszkiewicz raid_io->waitq_entry.cb_arg = raid_io; 370ae70d6a4SArtur Paszkiewicz spdk_bdev_queue_io_wait(bdev, ch, &raid_io->waitq_entry); 37107fe6a43SSeth Howell } 37207fe6a43SSeth Howell 3730ae5a89dSArtur Paszkiewicz static void 3742efe6d92SArtur Paszkiewicz raid_base_bdev_reset_complete(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg) 3752efe6d92SArtur Paszkiewicz { 3762efe6d92SArtur Paszkiewicz struct raid_bdev_io *raid_io = cb_arg; 3772efe6d92SArtur Paszkiewicz 3782efe6d92SArtur Paszkiewicz spdk_bdev_free_io(bdev_io); 3792efe6d92SArtur Paszkiewicz 3802efe6d92SArtur Paszkiewicz raid_bdev_io_complete_part(raid_io, 1, success ? 3812efe6d92SArtur Paszkiewicz SPDK_BDEV_IO_STATUS_SUCCESS : 3822efe6d92SArtur Paszkiewicz SPDK_BDEV_IO_STATUS_FAILED); 3832efe6d92SArtur Paszkiewicz } 3842efe6d92SArtur Paszkiewicz 3858dd1cd21SBen Walker static void raid_bdev_submit_reset_request(struct raid_bdev_io *raid_io); 3860ae5a89dSArtur Paszkiewicz 3870ae5a89dSArtur Paszkiewicz static void 388ae70d6a4SArtur Paszkiewicz _raid_bdev_submit_reset_request(void *_raid_io) 3890ae5a89dSArtur Paszkiewicz { 390ae70d6a4SArtur Paszkiewicz struct raid_bdev_io *raid_io = _raid_io; 3910ae5a89dSArtur Paszkiewicz 3920ae5a89dSArtur Paszkiewicz raid_bdev_submit_reset_request(raid_io); 3930ae5a89dSArtur Paszkiewicz } 3940ae5a89dSArtur Paszkiewicz 39507fe6a43SSeth Howell /* 39607fe6a43SSeth Howell * brief: 3970ae5a89dSArtur Paszkiewicz * raid_bdev_submit_reset_request function submits reset requests 39807fe6a43SSeth Howell * to member disks; it will submit as many as possible unless a reset fails with -ENOMEM, in 39907fe6a43SSeth Howell * which case it will queue it for later submission 40007fe6a43SSeth Howell * params: 4010ae5a89dSArtur Paszkiewicz * raid_io 40207fe6a43SSeth Howell * returns: 40307fe6a43SSeth Howell * none 40407fe6a43SSeth Howell */ 40507fe6a43SSeth Howell static void 4060ae5a89dSArtur Paszkiewicz raid_bdev_submit_reset_request(struct raid_bdev_io *raid_io) 40707fe6a43SSeth Howell { 40807fe6a43SSeth Howell struct raid_bdev *raid_bdev; 40907fe6a43SSeth Howell int ret; 41007fe6a43SSeth Howell uint8_t i; 411235cc2c9SArtur Paszkiewicz struct raid_base_bdev_info *base_info; 412235cc2c9SArtur Paszkiewicz struct spdk_io_channel *base_ch; 41307fe6a43SSeth Howell 414cb8dbf17SArtur Paszkiewicz raid_bdev = raid_io->raid_bdev; 41507fe6a43SSeth Howell 4162efe6d92SArtur Paszkiewicz if (raid_io->base_bdev_io_remaining == 0) { 4172efe6d92SArtur Paszkiewicz raid_io->base_bdev_io_remaining = raid_bdev->num_base_bdevs; 4182efe6d92SArtur Paszkiewicz } 41977b8618eSArtur Paszkiewicz 420fe7932a5SArtur Paszkiewicz for (i = raid_io->base_bdev_io_submitted; i < raid_bdev->num_base_bdevs; i++) { 421235cc2c9SArtur Paszkiewicz base_info = &raid_bdev->base_bdev_info[i]; 422235cc2c9SArtur Paszkiewicz base_ch = raid_io->raid_ch->base_channel[i]; 423b42cb0e5SArtur Paszkiewicz if (base_ch == NULL) { 424b42cb0e5SArtur Paszkiewicz raid_io->base_bdev_io_submitted++; 425b42cb0e5SArtur Paszkiewicz raid_bdev_io_complete_part(raid_io, 1, SPDK_BDEV_IO_STATUS_SUCCESS); 426b42cb0e5SArtur Paszkiewicz continue; 427b42cb0e5SArtur Paszkiewicz } 428235cc2c9SArtur Paszkiewicz ret = spdk_bdev_reset(base_info->desc, base_ch, 4292efe6d92SArtur Paszkiewicz raid_base_bdev_reset_complete, raid_io); 43007fe6a43SSeth Howell if (ret == 0) { 43107fe6a43SSeth Howell raid_io->base_bdev_io_submitted++; 432d3a04643SArtur Paszkiewicz } else if (ret == -ENOMEM) { 4338d1993a5SArtur Paszkiewicz raid_bdev_queue_io_wait(raid_io, spdk_bdev_desc_get_bdev(base_info->desc), 4348d1993a5SArtur Paszkiewicz base_ch, _raid_bdev_submit_reset_request); 435d3a04643SArtur Paszkiewicz return; 436d3a04643SArtur Paszkiewicz } else { 437d3a04643SArtur Paszkiewicz SPDK_ERRLOG("bdev io submit error not due to ENOMEM, it should not happen\n"); 438d3a04643SArtur Paszkiewicz assert(false); 4396ba11b19SArtur Paszkiewicz raid_bdev_io_complete(raid_io, SPDK_BDEV_IO_STATUS_FAILED); 44007fe6a43SSeth Howell return; 44107fe6a43SSeth Howell } 44207fe6a43SSeth Howell } 44307fe6a43SSeth Howell } 44407fe6a43SSeth Howell 44507fe6a43SSeth Howell /* 44607fe6a43SSeth Howell * brief: 44707fe6a43SSeth Howell * Callback function to spdk_bdev_io_get_buf. 44807fe6a43SSeth Howell * params: 44907fe6a43SSeth Howell * ch - pointer to raid bdev io channel 45007fe6a43SSeth Howell * bdev_io - pointer to parent bdev_io on raid bdev device 45107fe6a43SSeth Howell * success - True if buffer is allocated or false otherwise. 45207fe6a43SSeth Howell * returns: 45307fe6a43SSeth Howell * none 45407fe6a43SSeth Howell */ 45507fe6a43SSeth Howell static void 45607fe6a43SSeth Howell raid_bdev_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io, 45707fe6a43SSeth Howell bool success) 45807fe6a43SSeth Howell { 4590ae5a89dSArtur Paszkiewicz struct raid_bdev_io *raid_io = (struct raid_bdev_io *)bdev_io->driver_ctx; 4600ae5a89dSArtur Paszkiewicz 46107fe6a43SSeth Howell if (!success) { 4626ba11b19SArtur Paszkiewicz raid_bdev_io_complete(raid_io, SPDK_BDEV_IO_STATUS_FAILED); 46307fe6a43SSeth Howell return; 46407fe6a43SSeth Howell } 46507fe6a43SSeth Howell 466182278c0SArtur Paszkiewicz raid_io->raid_bdev->module->submit_rw_request(raid_io); 46707fe6a43SSeth Howell } 46807fe6a43SSeth Howell 46907fe6a43SSeth Howell /* 47007fe6a43SSeth Howell * brief: 47107fe6a43SSeth Howell * raid_bdev_submit_request function is the submit_request function pointer of 47207fe6a43SSeth Howell * raid bdev function table. This is used to submit the io on raid_bdev to below 47307fe6a43SSeth Howell * layers. 47407fe6a43SSeth Howell * params: 47507fe6a43SSeth Howell * ch - pointer to raid bdev io channel 47607fe6a43SSeth Howell * bdev_io - pointer to parent bdev_io on raid bdev device 47707fe6a43SSeth Howell * returns: 47807fe6a43SSeth Howell * none 47907fe6a43SSeth Howell */ 48007fe6a43SSeth Howell static void 48107fe6a43SSeth Howell raid_bdev_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io) 48207fe6a43SSeth Howell { 483485c7912SArtur Paszkiewicz struct raid_bdev_io *raid_io = (struct raid_bdev_io *)bdev_io->driver_ctx; 484485c7912SArtur Paszkiewicz 485cb8dbf17SArtur Paszkiewicz raid_io->raid_bdev = bdev_io->bdev->ctxt; 486485c7912SArtur Paszkiewicz raid_io->raid_ch = spdk_io_channel_get_ctx(ch); 4872efe6d92SArtur Paszkiewicz raid_io->base_bdev_io_remaining = 0; 488485c7912SArtur Paszkiewicz raid_io->base_bdev_io_submitted = 0; 489485c7912SArtur Paszkiewicz raid_io->base_bdev_io_status = SPDK_BDEV_IO_STATUS_SUCCESS; 490485c7912SArtur Paszkiewicz 49107fe6a43SSeth Howell switch (bdev_io->type) { 49207fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_READ: 49307fe6a43SSeth Howell spdk_bdev_io_get_buf(bdev_io, raid_bdev_get_buf_cb, 49407fe6a43SSeth Howell bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen); 49507fe6a43SSeth Howell break; 49607fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_WRITE: 497182278c0SArtur Paszkiewicz raid_io->raid_bdev->module->submit_rw_request(raid_io); 49807fe6a43SSeth Howell break; 49907fe6a43SSeth Howell 50007fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_RESET: 5010ae5a89dSArtur Paszkiewicz raid_bdev_submit_reset_request(raid_io); 50207fe6a43SSeth Howell break; 50307fe6a43SSeth Howell 50407fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_FLUSH: 50507fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_UNMAP: 506182278c0SArtur Paszkiewicz raid_io->raid_bdev->module->submit_null_payload_request(raid_io); 50707fe6a43SSeth Howell break; 50807fe6a43SSeth Howell 50907fe6a43SSeth Howell default: 51007fe6a43SSeth Howell SPDK_ERRLOG("submit request, invalid io type %u\n", bdev_io->type); 5116ba11b19SArtur Paszkiewicz raid_bdev_io_complete(raid_io, SPDK_BDEV_IO_STATUS_FAILED); 51207fe6a43SSeth Howell break; 51307fe6a43SSeth Howell } 51407fe6a43SSeth Howell } 51507fe6a43SSeth Howell 51607fe6a43SSeth Howell /* 51707fe6a43SSeth Howell * brief: 51807fe6a43SSeth Howell * _raid_bdev_io_type_supported checks whether io_type is supported in 51907fe6a43SSeth Howell * all base bdev modules of raid bdev module. If anyone among the base_bdevs 52007fe6a43SSeth Howell * doesn't support, the raid device doesn't supports. 52107fe6a43SSeth Howell * 52207fe6a43SSeth Howell * params: 52307fe6a43SSeth Howell * raid_bdev - pointer to raid bdev context 52407fe6a43SSeth Howell * io_type - io type 52507fe6a43SSeth Howell * returns: 52607fe6a43SSeth Howell * true - io_type is supported 52707fe6a43SSeth Howell * false - io_type is not supported 52807fe6a43SSeth Howell */ 52907fe6a43SSeth Howell inline static bool 53007fe6a43SSeth Howell _raid_bdev_io_type_supported(struct raid_bdev *raid_bdev, enum spdk_bdev_io_type io_type) 53107fe6a43SSeth Howell { 532a193dcb8SArtur Paszkiewicz struct raid_base_bdev_info *base_info; 53307fe6a43SSeth Howell 5341d3ca5c4SArtur Paszkiewicz if (io_type == SPDK_BDEV_IO_TYPE_FLUSH || 5351d3ca5c4SArtur Paszkiewicz io_type == SPDK_BDEV_IO_TYPE_UNMAP) { 5361d3ca5c4SArtur Paszkiewicz if (raid_bdev->module->submit_null_payload_request == NULL) { 5371d3ca5c4SArtur Paszkiewicz return false; 5381d3ca5c4SArtur Paszkiewicz } 5391d3ca5c4SArtur Paszkiewicz } 5401d3ca5c4SArtur Paszkiewicz 541a193dcb8SArtur Paszkiewicz RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) { 5428d1993a5SArtur Paszkiewicz if (base_info->desc == NULL) { 54307fe6a43SSeth Howell continue; 54407fe6a43SSeth Howell } 54507fe6a43SSeth Howell 5468d1993a5SArtur Paszkiewicz if (spdk_bdev_io_type_supported(spdk_bdev_desc_get_bdev(base_info->desc), io_type) == false) { 54707fe6a43SSeth Howell return false; 54807fe6a43SSeth Howell } 54907fe6a43SSeth Howell } 55007fe6a43SSeth Howell 55107fe6a43SSeth Howell return true; 55207fe6a43SSeth Howell } 55307fe6a43SSeth Howell 55407fe6a43SSeth Howell /* 55507fe6a43SSeth Howell * brief: 55607fe6a43SSeth Howell * raid_bdev_io_type_supported is the io_supported function for bdev function 55707fe6a43SSeth Howell * table which returns whether the particular io type is supported or not by 55807fe6a43SSeth Howell * raid bdev module 55907fe6a43SSeth Howell * params: 56007fe6a43SSeth Howell * ctx - pointer to raid bdev context 56107fe6a43SSeth Howell * type - io type 56207fe6a43SSeth Howell * returns: 56307fe6a43SSeth Howell * true - io_type is supported 56407fe6a43SSeth Howell * false - io_type is not supported 56507fe6a43SSeth Howell */ 56607fe6a43SSeth Howell static bool 56707fe6a43SSeth Howell raid_bdev_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type) 56807fe6a43SSeth Howell { 56907fe6a43SSeth Howell switch (io_type) { 57007fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_READ: 57107fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_WRITE: 57207fe6a43SSeth Howell return true; 57307fe6a43SSeth Howell 57407fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_FLUSH: 57507fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_RESET: 57607fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_UNMAP: 57707fe6a43SSeth Howell return _raid_bdev_io_type_supported(ctx, io_type); 57807fe6a43SSeth Howell 57907fe6a43SSeth Howell default: 58007fe6a43SSeth Howell return false; 58107fe6a43SSeth Howell } 58207fe6a43SSeth Howell 58307fe6a43SSeth Howell return false; 58407fe6a43SSeth Howell } 58507fe6a43SSeth Howell 58607fe6a43SSeth Howell /* 58707fe6a43SSeth Howell * brief: 58807fe6a43SSeth Howell * raid_bdev_get_io_channel is the get_io_channel function table pointer for 58907fe6a43SSeth Howell * raid bdev. This is used to return the io channel for this raid bdev 59007fe6a43SSeth Howell * params: 59107fe6a43SSeth Howell * ctxt - pointer to raid_bdev 59207fe6a43SSeth Howell * returns: 59307fe6a43SSeth Howell * pointer to io channel for raid bdev 59407fe6a43SSeth Howell */ 59507fe6a43SSeth Howell static struct spdk_io_channel * 59607fe6a43SSeth Howell raid_bdev_get_io_channel(void *ctxt) 59707fe6a43SSeth Howell { 59807fe6a43SSeth Howell struct raid_bdev *raid_bdev = ctxt; 59907fe6a43SSeth Howell 60007fe6a43SSeth Howell return spdk_get_io_channel(raid_bdev); 60107fe6a43SSeth Howell } 60207fe6a43SSeth Howell 603ec6d94b6SArtur Paszkiewicz void 604ec6d94b6SArtur Paszkiewicz raid_bdev_write_info_json(struct raid_bdev *raid_bdev, struct spdk_json_write_ctx *w) 60507fe6a43SSeth Howell { 606a193dcb8SArtur Paszkiewicz struct raid_base_bdev_info *base_info; 607b9792a95SArtur Paszkiewicz char uuid_str[SPDK_UUID_STRING_LEN]; 60807fe6a43SSeth Howell 60907fe6a43SSeth Howell assert(raid_bdev != NULL); 6104dd2a0d3SArtur Paszkiewicz assert(spdk_get_thread() == spdk_thread_get_app_thread()); 61107fe6a43SSeth Howell 612b9792a95SArtur Paszkiewicz spdk_uuid_fmt_lower(uuid_str, sizeof(uuid_str), &raid_bdev->bdev.uuid); 613b9792a95SArtur Paszkiewicz spdk_json_write_named_string(w, "uuid", uuid_str); 61407fe6a43SSeth Howell spdk_json_write_named_uint32(w, "strip_size_kb", raid_bdev->strip_size_kb); 61546ff15a6SArtur Paszkiewicz spdk_json_write_named_string(w, "state", raid_bdev_state_to_str(raid_bdev->state)); 616445e667fSArtur Paszkiewicz spdk_json_write_named_string(w, "raid_level", raid_bdev_level_to_str(raid_bdev->level)); 61777b8f7b6SArtur Paszkiewicz spdk_json_write_named_bool(w, "superblock", raid_bdev->sb != NULL); 61807fe6a43SSeth Howell spdk_json_write_named_uint32(w, "num_base_bdevs", raid_bdev->num_base_bdevs); 61907fe6a43SSeth Howell spdk_json_write_named_uint32(w, "num_base_bdevs_discovered", raid_bdev->num_base_bdevs_discovered); 62007fe6a43SSeth Howell spdk_json_write_name(w, "base_bdevs_list"); 62107fe6a43SSeth Howell spdk_json_write_array_begin(w); 622a193dcb8SArtur Paszkiewicz RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) { 623*c51db566SArtur Paszkiewicz spdk_json_write_object_begin(w); 624*c51db566SArtur Paszkiewicz spdk_json_write_name(w, "name"); 625*c51db566SArtur Paszkiewicz if (base_info->name) { 626*c51db566SArtur Paszkiewicz spdk_json_write_string(w, base_info->name); 62707fe6a43SSeth Howell } else { 62807fe6a43SSeth Howell spdk_json_write_null(w); 62907fe6a43SSeth Howell } 630*c51db566SArtur Paszkiewicz spdk_uuid_fmt_lower(uuid_str, sizeof(uuid_str), &base_info->uuid); 631*c51db566SArtur Paszkiewicz spdk_json_write_named_string(w, "uuid", uuid_str); 632*c51db566SArtur Paszkiewicz spdk_json_write_named_bool(w, "is_configured", base_info->is_configured); 633*c51db566SArtur Paszkiewicz spdk_json_write_named_uint64(w, "data_offset", base_info->data_offset); 634*c51db566SArtur Paszkiewicz spdk_json_write_named_uint64(w, "data_size", base_info->data_size); 635*c51db566SArtur Paszkiewicz spdk_json_write_object_end(w); 63607fe6a43SSeth Howell } 63707fe6a43SSeth Howell spdk_json_write_array_end(w); 638ec6d94b6SArtur Paszkiewicz } 639ec6d94b6SArtur Paszkiewicz 640ec6d94b6SArtur Paszkiewicz /* 641ec6d94b6SArtur Paszkiewicz * brief: 642ec6d94b6SArtur Paszkiewicz * raid_bdev_dump_info_json is the function table pointer for raid bdev 643ec6d94b6SArtur Paszkiewicz * params: 644ec6d94b6SArtur Paszkiewicz * ctx - pointer to raid_bdev 645ec6d94b6SArtur Paszkiewicz * w - pointer to json context 646ec6d94b6SArtur Paszkiewicz * returns: 647ec6d94b6SArtur Paszkiewicz * 0 - success 648ec6d94b6SArtur Paszkiewicz * non zero - failure 649ec6d94b6SArtur Paszkiewicz */ 650ec6d94b6SArtur Paszkiewicz static int 651ec6d94b6SArtur Paszkiewicz raid_bdev_dump_info_json(void *ctx, struct spdk_json_write_ctx *w) 652ec6d94b6SArtur Paszkiewicz { 653ec6d94b6SArtur Paszkiewicz struct raid_bdev *raid_bdev = ctx; 654ec6d94b6SArtur Paszkiewicz 655ec6d94b6SArtur Paszkiewicz SPDK_DEBUGLOG(bdev_raid, "raid_bdev_dump_config_json\n"); 656ec6d94b6SArtur Paszkiewicz 657ec6d94b6SArtur Paszkiewicz /* Dump the raid bdev configuration related information */ 658ec6d94b6SArtur Paszkiewicz spdk_json_write_named_object_begin(w, "raid"); 659ec6d94b6SArtur Paszkiewicz raid_bdev_write_info_json(raid_bdev, w); 66007fe6a43SSeth Howell spdk_json_write_object_end(w); 66107fe6a43SSeth Howell 66207fe6a43SSeth Howell return 0; 66307fe6a43SSeth Howell } 66407fe6a43SSeth Howell 66507fe6a43SSeth Howell /* 66607fe6a43SSeth Howell * brief: 66707fe6a43SSeth Howell * raid_bdev_write_config_json is the function table pointer for raid bdev 66807fe6a43SSeth Howell * params: 66907fe6a43SSeth Howell * bdev - pointer to spdk_bdev 67007fe6a43SSeth Howell * w - pointer to json context 67107fe6a43SSeth Howell * returns: 67207fe6a43SSeth Howell * none 67307fe6a43SSeth Howell */ 67407fe6a43SSeth Howell static void 67507fe6a43SSeth Howell raid_bdev_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w) 67607fe6a43SSeth Howell { 67707fe6a43SSeth Howell struct raid_bdev *raid_bdev = bdev->ctxt; 678a193dcb8SArtur Paszkiewicz struct raid_base_bdev_info *base_info; 679b9792a95SArtur Paszkiewicz char uuid_str[SPDK_UUID_STRING_LEN]; 68007fe6a43SSeth Howell 6814dd2a0d3SArtur Paszkiewicz assert(spdk_get_thread() == spdk_thread_get_app_thread()); 6824dd2a0d3SArtur Paszkiewicz 68377b8f7b6SArtur Paszkiewicz if (raid_bdev->sb != NULL) { 684deed7d2fSArtur Paszkiewicz /* raid bdev configuration is stored in the superblock */ 685deed7d2fSArtur Paszkiewicz return; 686deed7d2fSArtur Paszkiewicz } 687deed7d2fSArtur Paszkiewicz 68807fe6a43SSeth Howell spdk_json_write_object_begin(w); 68907fe6a43SSeth Howell 690f0731534SMaciej Wawryk spdk_json_write_named_string(w, "method", "bdev_raid_create"); 69107fe6a43SSeth Howell 69207fe6a43SSeth Howell spdk_json_write_named_object_begin(w, "params"); 69307fe6a43SSeth Howell spdk_json_write_named_string(w, "name", bdev->name); 694b9792a95SArtur Paszkiewicz spdk_uuid_fmt_lower(uuid_str, sizeof(uuid_str), &raid_bdev->bdev.uuid); 695b9792a95SArtur Paszkiewicz spdk_json_write_named_string(w, "uuid", uuid_str); 696af4fa148SWANGHAILIANG spdk_json_write_named_uint32(w, "strip_size_kb", raid_bdev->strip_size_kb); 697445e667fSArtur Paszkiewicz spdk_json_write_named_string(w, "raid_level", raid_bdev_level_to_str(raid_bdev->level)); 69877b8f7b6SArtur Paszkiewicz spdk_json_write_named_bool(w, "superblock", raid_bdev->sb != NULL); 69907fe6a43SSeth Howell 70007fe6a43SSeth Howell spdk_json_write_named_array_begin(w, "base_bdevs"); 701a193dcb8SArtur Paszkiewicz RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) { 7028d1993a5SArtur Paszkiewicz if (base_info->desc) { 7038d1993a5SArtur Paszkiewicz spdk_json_write_string(w, spdk_bdev_desc_get_bdev(base_info->desc)->name); 70407fe6a43SSeth Howell } 70507fe6a43SSeth Howell } 70607fe6a43SSeth Howell spdk_json_write_array_end(w); 70707fe6a43SSeth Howell spdk_json_write_object_end(w); 70807fe6a43SSeth Howell 70907fe6a43SSeth Howell spdk_json_write_object_end(w); 71007fe6a43SSeth Howell } 71107fe6a43SSeth Howell 712be440c01SAlexey Marchuk static int 713be440c01SAlexey Marchuk raid_bdev_get_memory_domains(void *ctx, struct spdk_memory_domain **domains, int array_size) 714be440c01SAlexey Marchuk { 715be440c01SAlexey Marchuk struct raid_bdev *raid_bdev = ctx; 716973b0d62SArtur Paszkiewicz struct raid_base_bdev_info *base_info; 717b42cb0e5SArtur Paszkiewicz int domains_count = 0, rc = 0; 718be440c01SAlexey Marchuk 71972672d49SArtur Paszkiewicz if (raid_bdev->module->memory_domains_supported == false) { 72072672d49SArtur Paszkiewicz return 0; 72172672d49SArtur Paszkiewicz } 72272672d49SArtur Paszkiewicz 723b42cb0e5SArtur Paszkiewicz spdk_spin_lock(&raid_bdev->base_bdev_lock); 724b42cb0e5SArtur Paszkiewicz 725be440c01SAlexey Marchuk /* First loop to get the number of memory domains */ 726973b0d62SArtur Paszkiewicz RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) { 7278d1993a5SArtur Paszkiewicz if (base_info->desc == NULL) { 728b42cb0e5SArtur Paszkiewicz continue; 729b42cb0e5SArtur Paszkiewicz } 7308d1993a5SArtur Paszkiewicz rc = spdk_bdev_get_memory_domains(spdk_bdev_desc_get_bdev(base_info->desc), NULL, 0); 731be440c01SAlexey Marchuk if (rc < 0) { 732b42cb0e5SArtur Paszkiewicz goto out; 733be440c01SAlexey Marchuk } 734be440c01SAlexey Marchuk domains_count += rc; 735be440c01SAlexey Marchuk } 736be440c01SAlexey Marchuk 737be440c01SAlexey Marchuk if (!domains || array_size < domains_count) { 738b42cb0e5SArtur Paszkiewicz goto out; 739be440c01SAlexey Marchuk } 740be440c01SAlexey Marchuk 741973b0d62SArtur Paszkiewicz RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) { 7428d1993a5SArtur Paszkiewicz if (base_info->desc == NULL) { 743b42cb0e5SArtur Paszkiewicz continue; 744b42cb0e5SArtur Paszkiewicz } 7458d1993a5SArtur Paszkiewicz rc = spdk_bdev_get_memory_domains(spdk_bdev_desc_get_bdev(base_info->desc), domains, array_size); 746be440c01SAlexey Marchuk if (rc < 0) { 747b42cb0e5SArtur Paszkiewicz goto out; 748be440c01SAlexey Marchuk } 749be440c01SAlexey Marchuk domains += rc; 750be440c01SAlexey Marchuk array_size -= rc; 751be440c01SAlexey Marchuk } 752b42cb0e5SArtur Paszkiewicz out: 753b42cb0e5SArtur Paszkiewicz spdk_spin_unlock(&raid_bdev->base_bdev_lock); 754b42cb0e5SArtur Paszkiewicz 755b42cb0e5SArtur Paszkiewicz if (rc < 0) { 756b42cb0e5SArtur Paszkiewicz return rc; 757b42cb0e5SArtur Paszkiewicz } 758be440c01SAlexey Marchuk 759be440c01SAlexey Marchuk return domains_count; 760be440c01SAlexey Marchuk } 761be440c01SAlexey Marchuk 76207fe6a43SSeth Howell /* g_raid_bdev_fn_table is the function table for raid bdev */ 76307fe6a43SSeth Howell static const struct spdk_bdev_fn_table g_raid_bdev_fn_table = { 76407fe6a43SSeth Howell .destruct = raid_bdev_destruct, 76507fe6a43SSeth Howell .submit_request = raid_bdev_submit_request, 76607fe6a43SSeth Howell .io_type_supported = raid_bdev_io_type_supported, 76707fe6a43SSeth Howell .get_io_channel = raid_bdev_get_io_channel, 76807fe6a43SSeth Howell .dump_info_json = raid_bdev_dump_info_json, 76907fe6a43SSeth Howell .write_config_json = raid_bdev_write_config_json, 770be440c01SAlexey Marchuk .get_memory_domains = raid_bdev_get_memory_domains, 77107fe6a43SSeth Howell }; 77207fe6a43SSeth Howell 773dccdd1e5SArtur Paszkiewicz struct raid_bdev * 774dccdd1e5SArtur Paszkiewicz raid_bdev_find_by_name(const char *name) 77507fe6a43SSeth Howell { 776dccdd1e5SArtur Paszkiewicz struct raid_bdev *raid_bdev; 77707fe6a43SSeth Howell 778dccdd1e5SArtur Paszkiewicz TAILQ_FOREACH(raid_bdev, &g_raid_bdev_list, global_link) { 779dccdd1e5SArtur Paszkiewicz if (strcmp(raid_bdev->bdev.name, name) == 0) { 780dccdd1e5SArtur Paszkiewicz return raid_bdev; 78107fe6a43SSeth Howell } 78207fe6a43SSeth Howell } 78307fe6a43SSeth Howell 784dccdd1e5SArtur Paszkiewicz return NULL; 78507fe6a43SSeth Howell } 786445e667fSArtur Paszkiewicz 787445e667fSArtur Paszkiewicz static struct { 788445e667fSArtur Paszkiewicz const char *name; 789445e667fSArtur Paszkiewicz enum raid_level value; 790445e667fSArtur Paszkiewicz } g_raid_level_names[] = { 791445e667fSArtur Paszkiewicz { "raid0", RAID0 }, 792445e667fSArtur Paszkiewicz { "0", RAID0 }, 793208f21cdSKrzysztof Smolinski { "raid1", RAID1 }, 794208f21cdSKrzysztof Smolinski { "1", RAID1 }, 79583a4b155SArtur Paszkiewicz { "raid5f", RAID5F }, 79683a4b155SArtur Paszkiewicz { "5f", RAID5F }, 79764eebbd1Syupeng { "concat", CONCAT }, 798445e667fSArtur Paszkiewicz { } 799445e667fSArtur Paszkiewicz }; 800445e667fSArtur Paszkiewicz 80146ff15a6SArtur Paszkiewicz static struct { 80246ff15a6SArtur Paszkiewicz const char *name; 80346ff15a6SArtur Paszkiewicz enum raid_bdev_state value; 80446ff15a6SArtur Paszkiewicz } g_raid_state_names[] = { 80546ff15a6SArtur Paszkiewicz { "online", RAID_BDEV_STATE_ONLINE }, 80646ff15a6SArtur Paszkiewicz { "configuring", RAID_BDEV_STATE_CONFIGURING }, 80746ff15a6SArtur Paszkiewicz { "offline", RAID_BDEV_STATE_OFFLINE }, 80846ff15a6SArtur Paszkiewicz { } 80946ff15a6SArtur Paszkiewicz }; 81046ff15a6SArtur Paszkiewicz 8118dd1cd21SBen Walker /* We have to use the typedef in the function declaration to appease astyle. */ 8128dd1cd21SBen Walker typedef enum raid_level raid_level_t; 81346ff15a6SArtur Paszkiewicz typedef enum raid_bdev_state raid_bdev_state_t; 8148dd1cd21SBen Walker 8158dd1cd21SBen Walker raid_level_t 81646ff15a6SArtur Paszkiewicz raid_bdev_str_to_level(const char *str) 817445e667fSArtur Paszkiewicz { 818445e667fSArtur Paszkiewicz unsigned int i; 819445e667fSArtur Paszkiewicz 820a2606d4bSMaciej Szwed assert(str != NULL); 821a2606d4bSMaciej Szwed 822445e667fSArtur Paszkiewicz for (i = 0; g_raid_level_names[i].name != NULL; i++) { 823445e667fSArtur Paszkiewicz if (strcasecmp(g_raid_level_names[i].name, str) == 0) { 824445e667fSArtur Paszkiewicz return g_raid_level_names[i].value; 825445e667fSArtur Paszkiewicz } 826445e667fSArtur Paszkiewicz } 827445e667fSArtur Paszkiewicz 828445e667fSArtur Paszkiewicz return INVALID_RAID_LEVEL; 829445e667fSArtur Paszkiewicz } 830445e667fSArtur Paszkiewicz 831445e667fSArtur Paszkiewicz const char * 832445e667fSArtur Paszkiewicz raid_bdev_level_to_str(enum raid_level level) 833445e667fSArtur Paszkiewicz { 834445e667fSArtur Paszkiewicz unsigned int i; 835445e667fSArtur Paszkiewicz 836445e667fSArtur Paszkiewicz for (i = 0; g_raid_level_names[i].name != NULL; i++) { 837445e667fSArtur Paszkiewicz if (g_raid_level_names[i].value == level) { 838445e667fSArtur Paszkiewicz return g_raid_level_names[i].name; 839445e667fSArtur Paszkiewicz } 840445e667fSArtur Paszkiewicz } 841445e667fSArtur Paszkiewicz 842445e667fSArtur Paszkiewicz return ""; 843445e667fSArtur Paszkiewicz } 844445e667fSArtur Paszkiewicz 84546ff15a6SArtur Paszkiewicz raid_bdev_state_t 84646ff15a6SArtur Paszkiewicz raid_bdev_str_to_state(const char *str) 84746ff15a6SArtur Paszkiewicz { 84846ff15a6SArtur Paszkiewicz unsigned int i; 84946ff15a6SArtur Paszkiewicz 85046ff15a6SArtur Paszkiewicz assert(str != NULL); 85146ff15a6SArtur Paszkiewicz 85246ff15a6SArtur Paszkiewicz for (i = 0; g_raid_state_names[i].name != NULL; i++) { 85346ff15a6SArtur Paszkiewicz if (strcasecmp(g_raid_state_names[i].name, str) == 0) { 85446ff15a6SArtur Paszkiewicz return g_raid_state_names[i].value; 85546ff15a6SArtur Paszkiewicz } 85646ff15a6SArtur Paszkiewicz } 85746ff15a6SArtur Paszkiewicz 85846ff15a6SArtur Paszkiewicz return RAID_BDEV_STATE_MAX; 85946ff15a6SArtur Paszkiewicz } 86046ff15a6SArtur Paszkiewicz 86146ff15a6SArtur Paszkiewicz const char * 86246ff15a6SArtur Paszkiewicz raid_bdev_state_to_str(enum raid_bdev_state state) 86346ff15a6SArtur Paszkiewicz { 86446ff15a6SArtur Paszkiewicz unsigned int i; 86546ff15a6SArtur Paszkiewicz 86646ff15a6SArtur Paszkiewicz for (i = 0; g_raid_state_names[i].name != NULL; i++) { 86746ff15a6SArtur Paszkiewicz if (g_raid_state_names[i].value == state) { 86846ff15a6SArtur Paszkiewicz return g_raid_state_names[i].name; 86946ff15a6SArtur Paszkiewicz } 87046ff15a6SArtur Paszkiewicz } 87146ff15a6SArtur Paszkiewicz 87246ff15a6SArtur Paszkiewicz assert(false); 87346ff15a6SArtur Paszkiewicz return ""; 87446ff15a6SArtur Paszkiewicz } 87546ff15a6SArtur Paszkiewicz 87607fe6a43SSeth Howell /* 87707fe6a43SSeth Howell * brief: 87807fe6a43SSeth Howell * raid_bdev_fini_start is called when bdev layer is starting the 87907fe6a43SSeth Howell * shutdown process 88007fe6a43SSeth Howell * params: 88107fe6a43SSeth Howell * none 88207fe6a43SSeth Howell * returns: 88307fe6a43SSeth Howell * none 88407fe6a43SSeth Howell */ 88507fe6a43SSeth Howell static void 88607fe6a43SSeth Howell raid_bdev_fini_start(void) 88707fe6a43SSeth Howell { 8882172c432STomasz Zawadzki SPDK_DEBUGLOG(bdev_raid, "raid_bdev_fini_start\n"); 88907fe6a43SSeth Howell g_shutdown_started = true; 89007fe6a43SSeth Howell } 89107fe6a43SSeth Howell 89207fe6a43SSeth Howell /* 89307fe6a43SSeth Howell * brief: 89407fe6a43SSeth Howell * raid_bdev_exit is called on raid bdev module exit time by bdev layer 89507fe6a43SSeth Howell * params: 89607fe6a43SSeth Howell * none 89707fe6a43SSeth Howell * returns: 89807fe6a43SSeth Howell * none 89907fe6a43SSeth Howell */ 90007fe6a43SSeth Howell static void 90107fe6a43SSeth Howell raid_bdev_exit(void) 90207fe6a43SSeth Howell { 903dccdd1e5SArtur Paszkiewicz struct raid_bdev *raid_bdev, *tmp; 90495a04949SArtur Paszkiewicz 9052172c432STomasz Zawadzki SPDK_DEBUGLOG(bdev_raid, "raid_bdev_exit\n"); 906dccdd1e5SArtur Paszkiewicz 907dccdd1e5SArtur Paszkiewicz TAILQ_FOREACH_SAFE(raid_bdev, &g_raid_bdev_list, global_link, tmp) { 908dccdd1e5SArtur Paszkiewicz raid_bdev_cleanup_and_free(raid_bdev); 90995a04949SArtur Paszkiewicz } 91007fe6a43SSeth Howell } 91107fe6a43SSeth Howell 91207fe6a43SSeth Howell /* 91307fe6a43SSeth Howell * brief: 91407fe6a43SSeth Howell * raid_bdev_get_ctx_size is used to return the context size of bdev_io for raid 91507fe6a43SSeth Howell * module 91607fe6a43SSeth Howell * params: 91707fe6a43SSeth Howell * none 91807fe6a43SSeth Howell * returns: 91907fe6a43SSeth Howell * size of spdk_bdev_io context for raid 92007fe6a43SSeth Howell */ 92107fe6a43SSeth Howell static int 92207fe6a43SSeth Howell raid_bdev_get_ctx_size(void) 92307fe6a43SSeth Howell { 9242172c432STomasz Zawadzki SPDK_DEBUGLOG(bdev_raid, "raid_bdev_get_ctx_size\n"); 92507fe6a43SSeth Howell return sizeof(struct raid_bdev_io); 92607fe6a43SSeth Howell } 92707fe6a43SSeth Howell 92807fe6a43SSeth Howell static struct spdk_bdev_module g_raid_if = { 92907fe6a43SSeth Howell .name = "raid", 93007fe6a43SSeth Howell .module_init = raid_bdev_init, 93107fe6a43SSeth Howell .fini_start = raid_bdev_fini_start, 93207fe6a43SSeth Howell .module_fini = raid_bdev_exit, 93307fe6a43SSeth Howell .get_ctx_size = raid_bdev_get_ctx_size, 9348a6bb6a8SArtur Paszkiewicz .examine_disk = raid_bdev_examine, 93507fe6a43SSeth Howell .async_init = false, 93607fe6a43SSeth Howell .async_fini = false, 93707fe6a43SSeth Howell }; 93807fe6a43SSeth Howell SPDK_BDEV_MODULE_REGISTER(raid, &g_raid_if) 93907fe6a43SSeth Howell 94007fe6a43SSeth Howell /* 94107fe6a43SSeth Howell * brief: 94207fe6a43SSeth Howell * raid_bdev_init is the initialization function for raid bdev module 94307fe6a43SSeth Howell * params: 94407fe6a43SSeth Howell * none 94507fe6a43SSeth Howell * returns: 94607fe6a43SSeth Howell * 0 - success 94707fe6a43SSeth Howell * non zero - failure 94807fe6a43SSeth Howell */ 94907fe6a43SSeth Howell static int 95007fe6a43SSeth Howell raid_bdev_init(void) 95107fe6a43SSeth Howell { 95207fe6a43SSeth Howell return 0; 95307fe6a43SSeth Howell } 95407fe6a43SSeth Howell 95577b8f7b6SArtur Paszkiewicz static int 95677b8f7b6SArtur Paszkiewicz _raid_bdev_create(const char *name, uint32_t strip_size, uint8_t num_base_bdevs, 957deed7d2fSArtur Paszkiewicz enum raid_level level, bool superblock_enabled, const struct spdk_uuid *uuid, 958deed7d2fSArtur Paszkiewicz struct raid_bdev **raid_bdev_out) 95907fe6a43SSeth Howell { 96007fe6a43SSeth Howell struct raid_bdev *raid_bdev; 96107fe6a43SSeth Howell struct spdk_bdev *raid_bdev_gen; 9620a5194faSArtur Paszkiewicz struct raid_bdev_module *module; 96326861b70SArtur Paszkiewicz struct raid_base_bdev_info *base_info; 964ad94094fSKrzysztof Smolinski uint8_t min_operational; 9650a5194faSArtur Paszkiewicz 96677b8f7b6SArtur Paszkiewicz if (strnlen(name, RAID_BDEV_SB_NAME_SIZE) == RAID_BDEV_SB_NAME_SIZE) { 96777b8f7b6SArtur Paszkiewicz SPDK_ERRLOG("Raid bdev name '%s' exceeds %d characters\n", name, RAID_BDEV_SB_NAME_SIZE - 1); 96877b8f7b6SArtur Paszkiewicz return -EINVAL; 96977b8f7b6SArtur Paszkiewicz } 97077b8f7b6SArtur Paszkiewicz 971dccdd1e5SArtur Paszkiewicz if (raid_bdev_find_by_name(name) != NULL) { 972dccdd1e5SArtur Paszkiewicz SPDK_ERRLOG("Duplicate raid bdev name found: %s\n", name); 973dccdd1e5SArtur Paszkiewicz return -EEXIST; 974dccdd1e5SArtur Paszkiewicz } 975dccdd1e5SArtur Paszkiewicz 976208f21cdSKrzysztof Smolinski if (level == RAID1) { 977208f21cdSKrzysztof Smolinski if (strip_size != 0) { 978208f21cdSKrzysztof Smolinski SPDK_ERRLOG("Strip size is not supported by raid1\n"); 979208f21cdSKrzysztof Smolinski return -EINVAL; 980208f21cdSKrzysztof Smolinski } 981208f21cdSKrzysztof Smolinski } else if (spdk_u32_is_pow2(strip_size) == false) { 982dccdd1e5SArtur Paszkiewicz SPDK_ERRLOG("Invalid strip size %" PRIu32 "\n", strip_size); 983dccdd1e5SArtur Paszkiewicz return -EINVAL; 984dccdd1e5SArtur Paszkiewicz } 985dccdd1e5SArtur Paszkiewicz 986dccdd1e5SArtur Paszkiewicz module = raid_bdev_module_find(level); 9870a5194faSArtur Paszkiewicz if (module == NULL) { 988dccdd1e5SArtur Paszkiewicz SPDK_ERRLOG("Unsupported raid level '%d'\n", level); 9890a5194faSArtur Paszkiewicz return -EINVAL; 9900a5194faSArtur Paszkiewicz } 9910a5194faSArtur Paszkiewicz 9920a5194faSArtur Paszkiewicz assert(module->base_bdevs_min != 0); 993dccdd1e5SArtur Paszkiewicz if (num_base_bdevs < module->base_bdevs_min) { 9940a5194faSArtur Paszkiewicz SPDK_ERRLOG("At least %u base devices required for %s\n", 9950a5194faSArtur Paszkiewicz module->base_bdevs_min, 996dccdd1e5SArtur Paszkiewicz raid_bdev_level_to_str(level)); 9970a5194faSArtur Paszkiewicz return -EINVAL; 9980a5194faSArtur Paszkiewicz } 99907fe6a43SSeth Howell 1000ad94094fSKrzysztof Smolinski switch (module->base_bdevs_constraint.type) { 1001ad94094fSKrzysztof Smolinski case CONSTRAINT_MAX_BASE_BDEVS_REMOVED: 1002ad94094fSKrzysztof Smolinski min_operational = num_base_bdevs - module->base_bdevs_constraint.value; 1003ad94094fSKrzysztof Smolinski break; 1004ad94094fSKrzysztof Smolinski case CONSTRAINT_MIN_BASE_BDEVS_OPERATIONAL: 1005ad94094fSKrzysztof Smolinski min_operational = module->base_bdevs_constraint.value; 1006ad94094fSKrzysztof Smolinski break; 1007ad94094fSKrzysztof Smolinski case CONSTRAINT_UNSET: 1008ad94094fSKrzysztof Smolinski if (module->base_bdevs_constraint.value != 0) { 1009ad94094fSKrzysztof Smolinski SPDK_ERRLOG("Unexpected constraint value '%u' provided for raid bdev '%s'.\n", 1010ad94094fSKrzysztof Smolinski (uint8_t)module->base_bdevs_constraint.value, name); 1011ad94094fSKrzysztof Smolinski return -EINVAL; 1012ad94094fSKrzysztof Smolinski } 1013ad94094fSKrzysztof Smolinski min_operational = num_base_bdevs; 1014ad94094fSKrzysztof Smolinski break; 1015ad94094fSKrzysztof Smolinski default: 1016ad94094fSKrzysztof Smolinski SPDK_ERRLOG("Unrecognised constraint type '%u' in module for raid level '%s'.\n", 1017ad94094fSKrzysztof Smolinski (uint8_t)module->base_bdevs_constraint.type, 1018ad94094fSKrzysztof Smolinski raid_bdev_level_to_str(module->level)); 1019ad94094fSKrzysztof Smolinski return -EINVAL; 1020ad94094fSKrzysztof Smolinski }; 1021ad94094fSKrzysztof Smolinski 1022ad94094fSKrzysztof Smolinski if (min_operational == 0 || min_operational > num_base_bdevs) { 1023ad94094fSKrzysztof Smolinski SPDK_ERRLOG("Wrong constraint value for raid level '%s'.\n", 1024ad94094fSKrzysztof Smolinski raid_bdev_level_to_str(module->level)); 1025ad94094fSKrzysztof Smolinski return -EINVAL; 1026ad94094fSKrzysztof Smolinski } 1027ad94094fSKrzysztof Smolinski 102807fe6a43SSeth Howell raid_bdev = calloc(1, sizeof(*raid_bdev)); 102907fe6a43SSeth Howell if (!raid_bdev) { 103007fe6a43SSeth Howell SPDK_ERRLOG("Unable to allocate memory for raid bdev\n"); 103107fe6a43SSeth Howell return -ENOMEM; 103207fe6a43SSeth Howell } 103307fe6a43SSeth Howell 1034fbdb05f0SArtur Paszkiewicz spdk_spin_init(&raid_bdev->base_bdev_lock); 10350a5194faSArtur Paszkiewicz raid_bdev->module = module; 1036dccdd1e5SArtur Paszkiewicz raid_bdev->num_base_bdevs = num_base_bdevs; 103707fe6a43SSeth Howell raid_bdev->base_bdev_info = calloc(raid_bdev->num_base_bdevs, 103807fe6a43SSeth Howell sizeof(struct raid_base_bdev_info)); 103907fe6a43SSeth Howell if (!raid_bdev->base_bdev_info) { 104007fe6a43SSeth Howell SPDK_ERRLOG("Unable able to allocate base bdev info\n"); 1041fbdb05f0SArtur Paszkiewicz raid_bdev_free(raid_bdev); 104207fe6a43SSeth Howell return -ENOMEM; 104307fe6a43SSeth Howell } 104407fe6a43SSeth Howell 104526861b70SArtur Paszkiewicz RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) { 104626861b70SArtur Paszkiewicz base_info->raid_bdev = raid_bdev; 104726861b70SArtur Paszkiewicz } 104826861b70SArtur Paszkiewicz 104907fe6a43SSeth Howell /* strip_size_kb is from the rpc param. strip_size is in blocks and used 105017f7cf9bSpaul luse * internally and set later. 105107fe6a43SSeth Howell */ 105207fe6a43SSeth Howell raid_bdev->strip_size = 0; 1053dccdd1e5SArtur Paszkiewicz raid_bdev->strip_size_kb = strip_size; 105407fe6a43SSeth Howell raid_bdev->state = RAID_BDEV_STATE_CONFIGURING; 1055dccdd1e5SArtur Paszkiewicz raid_bdev->level = level; 1056ad94094fSKrzysztof Smolinski raid_bdev->min_base_bdevs_operational = min_operational; 105777b8f7b6SArtur Paszkiewicz 105877b8f7b6SArtur Paszkiewicz if (superblock_enabled) { 105977b8f7b6SArtur Paszkiewicz raid_bdev->sb = spdk_dma_zmalloc(RAID_BDEV_SB_MAX_LENGTH, 0x1000, NULL); 106077b8f7b6SArtur Paszkiewicz if (!raid_bdev->sb) { 106177b8f7b6SArtur Paszkiewicz SPDK_ERRLOG("Failed to allocate raid bdev sb buffer\n"); 106277b8f7b6SArtur Paszkiewicz raid_bdev_free(raid_bdev); 106377b8f7b6SArtur Paszkiewicz return -ENOMEM; 106477b8f7b6SArtur Paszkiewicz } 106577b8f7b6SArtur Paszkiewicz } 1066576729edSpaul luse 106707fe6a43SSeth Howell raid_bdev_gen = &raid_bdev->bdev; 106807fe6a43SSeth Howell 1069dccdd1e5SArtur Paszkiewicz raid_bdev_gen->name = strdup(name); 107007fe6a43SSeth Howell if (!raid_bdev_gen->name) { 107107fe6a43SSeth Howell SPDK_ERRLOG("Unable to allocate name for raid\n"); 1072fbdb05f0SArtur Paszkiewicz raid_bdev_free(raid_bdev); 107307fe6a43SSeth Howell return -ENOMEM; 107407fe6a43SSeth Howell } 107507fe6a43SSeth Howell 107607fe6a43SSeth Howell raid_bdev_gen->product_name = "Raid Volume"; 107707fe6a43SSeth Howell raid_bdev_gen->ctxt = raid_bdev; 107807fe6a43SSeth Howell raid_bdev_gen->fn_table = &g_raid_bdev_fn_table; 107907fe6a43SSeth Howell raid_bdev_gen->module = &g_raid_if; 108007fe6a43SSeth Howell raid_bdev_gen->write_cache = 0; 10811db41324SKrzysztof Karas spdk_uuid_copy(&raid_bdev_gen->uuid, uuid); 10821db41324SKrzysztof Karas 108307fe6a43SSeth Howell TAILQ_INSERT_TAIL(&g_raid_bdev_list, raid_bdev, global_link); 108407fe6a43SSeth Howell 1085dccdd1e5SArtur Paszkiewicz *raid_bdev_out = raid_bdev; 108607fe6a43SSeth Howell 108707fe6a43SSeth Howell return 0; 108807fe6a43SSeth Howell } 108907fe6a43SSeth Howell 109007fe6a43SSeth Howell /* 109107fe6a43SSeth Howell * brief: 109277b8f7b6SArtur Paszkiewicz * raid_bdev_create allocates raid bdev based on passed configuration 109377b8f7b6SArtur Paszkiewicz * params: 109477b8f7b6SArtur Paszkiewicz * name - name for raid bdev 109577b8f7b6SArtur Paszkiewicz * strip_size - strip size in KB 109677b8f7b6SArtur Paszkiewicz * num_base_bdevs - number of base bdevs 109777b8f7b6SArtur Paszkiewicz * level - raid level 109877b8f7b6SArtur Paszkiewicz * superblock_enabled - true if raid should have superblock 109977b8f7b6SArtur Paszkiewicz * uuid - uuid to set for the bdev 110077b8f7b6SArtur Paszkiewicz * raid_bdev_out - the created raid bdev 110177b8f7b6SArtur Paszkiewicz * returns: 110277b8f7b6SArtur Paszkiewicz * 0 - success 110377b8f7b6SArtur Paszkiewicz * non zero - failure 110477b8f7b6SArtur Paszkiewicz */ 110577b8f7b6SArtur Paszkiewicz int 110677b8f7b6SArtur Paszkiewicz raid_bdev_create(const char *name, uint32_t strip_size, uint8_t num_base_bdevs, 110777b8f7b6SArtur Paszkiewicz enum raid_level level, bool superblock_enabled, const struct spdk_uuid *uuid, 110877b8f7b6SArtur Paszkiewicz struct raid_bdev **raid_bdev_out) 110977b8f7b6SArtur Paszkiewicz { 111077b8f7b6SArtur Paszkiewicz struct raid_bdev *raid_bdev; 111177b8f7b6SArtur Paszkiewicz int rc; 111277b8f7b6SArtur Paszkiewicz 111377b8f7b6SArtur Paszkiewicz assert(uuid != NULL); 111477b8f7b6SArtur Paszkiewicz 111577b8f7b6SArtur Paszkiewicz rc = _raid_bdev_create(name, strip_size, num_base_bdevs, level, superblock_enabled, uuid, 111677b8f7b6SArtur Paszkiewicz &raid_bdev); 111777b8f7b6SArtur Paszkiewicz if (rc != 0) { 111877b8f7b6SArtur Paszkiewicz return rc; 111977b8f7b6SArtur Paszkiewicz } 112077b8f7b6SArtur Paszkiewicz 112177b8f7b6SArtur Paszkiewicz if (superblock_enabled && spdk_uuid_is_null(uuid)) { 112277b8f7b6SArtur Paszkiewicz /* we need to have the uuid to store in the superblock before the bdev is registered */ 112377b8f7b6SArtur Paszkiewicz spdk_uuid_generate(&raid_bdev->bdev.uuid); 112477b8f7b6SArtur Paszkiewicz } 112577b8f7b6SArtur Paszkiewicz 112677b8f7b6SArtur Paszkiewicz *raid_bdev_out = raid_bdev; 112777b8f7b6SArtur Paszkiewicz 112877b8f7b6SArtur Paszkiewicz return 0; 112977b8f7b6SArtur Paszkiewicz } 113077b8f7b6SArtur Paszkiewicz 113177b8f7b6SArtur Paszkiewicz /* 113277b8f7b6SArtur Paszkiewicz * brief: 1133357c038cSKrzysztof Smolinski * Check underlying block devices against support for metadata. Do not configure 1134357c038cSKrzysztof Smolinski * md support when parameters from block devices are inconsistent. 1135357c038cSKrzysztof Smolinski * params: 1136357c038cSKrzysztof Smolinski * raid_bdev - pointer to raid bdev 1137357c038cSKrzysztof Smolinski * returns: 1138357c038cSKrzysztof Smolinski * 0 - The raid bdev md parameters were successfully configured. 1139357c038cSKrzysztof Smolinski * non zero - Failed to configure md. 1140357c038cSKrzysztof Smolinski */ 1141357c038cSKrzysztof Smolinski static int 1142357c038cSKrzysztof Smolinski raid_bdev_configure_md(struct raid_bdev *raid_bdev) 1143357c038cSKrzysztof Smolinski { 1144357c038cSKrzysztof Smolinski struct spdk_bdev *base_bdev; 1145357c038cSKrzysztof Smolinski uint8_t i; 1146357c038cSKrzysztof Smolinski 1147357c038cSKrzysztof Smolinski for (i = 0; i < raid_bdev->num_base_bdevs; i++) { 11488d1993a5SArtur Paszkiewicz base_bdev = spdk_bdev_desc_get_bdev(raid_bdev->base_bdev_info[i].desc); 1149357c038cSKrzysztof Smolinski 1150c91f8b18SSlawomir Ptak /* Currently, RAID bdevs do not support DIF or DIX, so a RAID bdev cannot 1151c91f8b18SSlawomir Ptak * be created on top of any bdev which supports it */ 1152c91f8b18SSlawomir Ptak if (spdk_bdev_get_dif_type(base_bdev) != SPDK_DIF_DISABLE) { 1153c91f8b18SSlawomir Ptak SPDK_ERRLOG("at least one base bdev has DIF or DIX enabled " 1154c91f8b18SSlawomir Ptak "- unsupported RAID configuration\n"); 1155c91f8b18SSlawomir Ptak return -EPERM; 1156c91f8b18SSlawomir Ptak } 1157c91f8b18SSlawomir Ptak 1158357c038cSKrzysztof Smolinski if (i == 0) { 1159357c038cSKrzysztof Smolinski raid_bdev->bdev.md_len = spdk_bdev_get_md_size(base_bdev); 1160357c038cSKrzysztof Smolinski raid_bdev->bdev.md_interleave = spdk_bdev_is_md_interleaved(base_bdev); 1161357c038cSKrzysztof Smolinski continue; 1162357c038cSKrzysztof Smolinski } 1163357c038cSKrzysztof Smolinski 1164357c038cSKrzysztof Smolinski if (raid_bdev->bdev.md_len != spdk_bdev_get_md_size(base_bdev) || 1165c91f8b18SSlawomir Ptak raid_bdev->bdev.md_interleave != spdk_bdev_is_md_interleaved(base_bdev)) { 1166357c038cSKrzysztof Smolinski SPDK_ERRLOG("base bdevs are configured with different metadata formats\n"); 1167357c038cSKrzysztof Smolinski return -EPERM; 1168357c038cSKrzysztof Smolinski } 1169357c038cSKrzysztof Smolinski } 1170357c038cSKrzysztof Smolinski 1171357c038cSKrzysztof Smolinski return 0; 1172357c038cSKrzysztof Smolinski } 1173357c038cSKrzysztof Smolinski 117477b8f7b6SArtur Paszkiewicz static void 117577b8f7b6SArtur Paszkiewicz raid_bdev_configure_cont(struct raid_bdev *raid_bdev) 117677b8f7b6SArtur Paszkiewicz { 117777b8f7b6SArtur Paszkiewicz struct spdk_bdev *raid_bdev_gen = &raid_bdev->bdev; 117877b8f7b6SArtur Paszkiewicz int rc; 117977b8f7b6SArtur Paszkiewicz 118077b8f7b6SArtur Paszkiewicz raid_bdev->state = RAID_BDEV_STATE_ONLINE; 118177b8f7b6SArtur Paszkiewicz SPDK_DEBUGLOG(bdev_raid, "io device register %p\n", raid_bdev); 118277b8f7b6SArtur Paszkiewicz SPDK_DEBUGLOG(bdev_raid, "blockcnt %" PRIu64 ", blocklen %u\n", 118377b8f7b6SArtur Paszkiewicz raid_bdev_gen->blockcnt, raid_bdev_gen->blocklen); 118477b8f7b6SArtur Paszkiewicz spdk_io_device_register(raid_bdev, raid_bdev_create_cb, raid_bdev_destroy_cb, 118577b8f7b6SArtur Paszkiewicz sizeof(struct raid_bdev_io_channel), 118677b8f7b6SArtur Paszkiewicz raid_bdev_gen->name); 118777b8f7b6SArtur Paszkiewicz rc = spdk_bdev_register(raid_bdev_gen); 118877b8f7b6SArtur Paszkiewicz if (rc != 0) { 118977b8f7b6SArtur Paszkiewicz SPDK_ERRLOG("Unable to register raid bdev and stay at configuring state\n"); 119077b8f7b6SArtur Paszkiewicz if (raid_bdev->module->stop != NULL) { 119177b8f7b6SArtur Paszkiewicz raid_bdev->module->stop(raid_bdev); 119277b8f7b6SArtur Paszkiewicz } 119377b8f7b6SArtur Paszkiewicz spdk_io_device_unregister(raid_bdev, NULL); 119477b8f7b6SArtur Paszkiewicz raid_bdev->state = RAID_BDEV_STATE_CONFIGURING; 119577b8f7b6SArtur Paszkiewicz return; 119677b8f7b6SArtur Paszkiewicz } 119777b8f7b6SArtur Paszkiewicz SPDK_DEBUGLOG(bdev_raid, "raid bdev generic %p\n", raid_bdev_gen); 119877b8f7b6SArtur Paszkiewicz SPDK_DEBUGLOG(bdev_raid, "raid bdev is created with name %s, raid_bdev %p\n", 119977b8f7b6SArtur Paszkiewicz raid_bdev_gen->name, raid_bdev); 120077b8f7b6SArtur Paszkiewicz } 120177b8f7b6SArtur Paszkiewicz 120277b8f7b6SArtur Paszkiewicz static void 120377b8f7b6SArtur Paszkiewicz raid_bdev_configure_write_sb_cb(int status, struct raid_bdev *raid_bdev, void *ctx) 120477b8f7b6SArtur Paszkiewicz { 120577b8f7b6SArtur Paszkiewicz if (status == 0) { 120677b8f7b6SArtur Paszkiewicz raid_bdev_configure_cont(raid_bdev); 120777b8f7b6SArtur Paszkiewicz } else { 120877b8f7b6SArtur Paszkiewicz SPDK_ERRLOG("Failed to write raid bdev '%s' superblock: %s\n", 120977b8f7b6SArtur Paszkiewicz raid_bdev->bdev.name, spdk_strerror(-status)); 121077b8f7b6SArtur Paszkiewicz if (raid_bdev->module->stop != NULL) { 121177b8f7b6SArtur Paszkiewicz raid_bdev->module->stop(raid_bdev); 121277b8f7b6SArtur Paszkiewicz } 121377b8f7b6SArtur Paszkiewicz } 121477b8f7b6SArtur Paszkiewicz } 121577b8f7b6SArtur Paszkiewicz 1216357c038cSKrzysztof Smolinski /* 1217357c038cSKrzysztof Smolinski * brief: 121807fe6a43SSeth Howell * If raid bdev config is complete, then only register the raid bdev to 121907fe6a43SSeth Howell * bdev layer and remove this raid bdev from configuring list and 122007fe6a43SSeth Howell * insert the raid bdev to configured list 122107fe6a43SSeth Howell * params: 122207fe6a43SSeth Howell * raid_bdev - pointer to raid bdev 122307fe6a43SSeth Howell * returns: 122407fe6a43SSeth Howell * 0 - success 122507fe6a43SSeth Howell * non zero - failure 122607fe6a43SSeth Howell */ 122707fe6a43SSeth Howell static int 122807fe6a43SSeth Howell raid_bdev_configure(struct raid_bdev *raid_bdev) 122907fe6a43SSeth Howell { 1230a193dcb8SArtur Paszkiewicz uint32_t blocklen = 0; 1231a193dcb8SArtur Paszkiewicz struct raid_base_bdev_info *base_info; 12328d1993a5SArtur Paszkiewicz struct spdk_bdev *base_bdev; 123307fe6a43SSeth Howell int rc = 0; 123407fe6a43SSeth Howell 123594ea8754SArtur Paszkiewicz assert(raid_bdev->state == RAID_BDEV_STATE_CONFIGURING); 123694ea8754SArtur Paszkiewicz assert(raid_bdev->num_base_bdevs_discovered == raid_bdev->num_base_bdevs); 123794ea8754SArtur Paszkiewicz 1238a193dcb8SArtur Paszkiewicz RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) { 12398d1993a5SArtur Paszkiewicz assert(base_info->desc != NULL); 12408d1993a5SArtur Paszkiewicz base_bdev = spdk_bdev_desc_get_bdev(base_info->desc); 124107fe6a43SSeth Howell /* Check blocklen for all base bdevs that it should be same */ 1242a193dcb8SArtur Paszkiewicz if (blocklen == 0) { 12438d1993a5SArtur Paszkiewicz blocklen = base_bdev->blocklen; 12448d1993a5SArtur Paszkiewicz } else if (blocklen != base_bdev->blocklen) { 124507fe6a43SSeth Howell /* 124607fe6a43SSeth Howell * Assumption is that all the base bdevs for any raid bdev should 124707fe6a43SSeth Howell * have same blocklen 124807fe6a43SSeth Howell */ 124907fe6a43SSeth Howell SPDK_ERRLOG("Blocklen of various bdevs not matching\n"); 125007fe6a43SSeth Howell return -EINVAL; 125107fe6a43SSeth Howell } 125207fe6a43SSeth Howell } 125379bde4d3SArtur Paszkiewicz assert(blocklen > 0); 125407fe6a43SSeth Howell 125507fe6a43SSeth Howell /* The strip_size_kb is read in from user in KB. Convert to blocks here for 125607fe6a43SSeth Howell * internal use. 125707fe6a43SSeth Howell */ 125807fe6a43SSeth Howell raid_bdev->strip_size = (raid_bdev->strip_size_kb * 1024) / blocklen; 125931ce6cd8SArtur Paszkiewicz if (raid_bdev->strip_size == 0 && raid_bdev->level != RAID1) { 126031ce6cd8SArtur Paszkiewicz SPDK_ERRLOG("Strip size cannot be smaller than the device block size\n"); 126131ce6cd8SArtur Paszkiewicz return -EINVAL; 126231ce6cd8SArtur Paszkiewicz } 126307fe6a43SSeth Howell raid_bdev->strip_size_shift = spdk_u32log2(raid_bdev->strip_size); 126407fe6a43SSeth Howell raid_bdev->blocklen_shift = spdk_u32log2(blocklen); 126577b8f7b6SArtur Paszkiewicz raid_bdev->bdev.blocklen = blocklen; 12660b4ca522SArtur Paszkiewicz 1267357c038cSKrzysztof Smolinski rc = raid_bdev_configure_md(raid_bdev); 1268357c038cSKrzysztof Smolinski if (rc != 0) { 1269357c038cSKrzysztof Smolinski SPDK_ERRLOG("raid metadata configuration failed\n"); 1270357c038cSKrzysztof Smolinski return rc; 1271357c038cSKrzysztof Smolinski } 1272357c038cSKrzysztof Smolinski 12730b4ca522SArtur Paszkiewicz rc = raid_bdev->module->start(raid_bdev); 12740b4ca522SArtur Paszkiewicz if (rc != 0) { 12750b4ca522SArtur Paszkiewicz SPDK_ERRLOG("raid module startup callback failed\n"); 12760b4ca522SArtur Paszkiewicz return rc; 127707fe6a43SSeth Howell } 127877b8f7b6SArtur Paszkiewicz 127977b8f7b6SArtur Paszkiewicz if (raid_bdev->sb != NULL) { 12808a6bb6a8SArtur Paszkiewicz if (spdk_uuid_is_null(&raid_bdev->sb->uuid)) { 12818a6bb6a8SArtur Paszkiewicz /* NULL UUID is not valid in the sb so it means that we are creating a new 12828a6bb6a8SArtur Paszkiewicz * raid bdev and should initialize the superblock. 12838a6bb6a8SArtur Paszkiewicz */ 128477b8f7b6SArtur Paszkiewicz raid_bdev_init_superblock(raid_bdev); 12858a6bb6a8SArtur Paszkiewicz } else { 12868a6bb6a8SArtur Paszkiewicz assert(spdk_uuid_compare(&raid_bdev->sb->uuid, &raid_bdev->bdev.uuid) == 0); 12878a6bb6a8SArtur Paszkiewicz if (raid_bdev->sb->block_size != blocklen) { 12888a6bb6a8SArtur Paszkiewicz SPDK_ERRLOG("blocklen does not match value in superblock\n"); 12898a6bb6a8SArtur Paszkiewicz rc = -EINVAL; 12908a6bb6a8SArtur Paszkiewicz } 12918a6bb6a8SArtur Paszkiewicz if (raid_bdev->sb->raid_size != raid_bdev->bdev.blockcnt) { 12928a6bb6a8SArtur Paszkiewicz SPDK_ERRLOG("blockcnt does not match value in superblock\n"); 12938a6bb6a8SArtur Paszkiewicz rc = -EINVAL; 12948a6bb6a8SArtur Paszkiewicz } 12958a6bb6a8SArtur Paszkiewicz if (rc != 0) { 12968a6bb6a8SArtur Paszkiewicz if (raid_bdev->module->stop != NULL) { 12978a6bb6a8SArtur Paszkiewicz raid_bdev->module->stop(raid_bdev); 12988a6bb6a8SArtur Paszkiewicz } 12998a6bb6a8SArtur Paszkiewicz return rc; 13008a6bb6a8SArtur Paszkiewicz } 13018a6bb6a8SArtur Paszkiewicz } 13028a6bb6a8SArtur Paszkiewicz 130377b8f7b6SArtur Paszkiewicz raid_bdev_write_superblock(raid_bdev, raid_bdev_configure_write_sb_cb, NULL); 130477b8f7b6SArtur Paszkiewicz } else { 130577b8f7b6SArtur Paszkiewicz raid_bdev_configure_cont(raid_bdev); 13060b4ca522SArtur Paszkiewicz } 130707fe6a43SSeth Howell 130807fe6a43SSeth Howell return 0; 130907fe6a43SSeth Howell } 131007fe6a43SSeth Howell 131107fe6a43SSeth Howell /* 131207fe6a43SSeth Howell * brief: 131307fe6a43SSeth Howell * If raid bdev is online and registered, change the bdev state to 131407fe6a43SSeth Howell * configuring and unregister this raid device. Queue this raid device 131507fe6a43SSeth Howell * in configuring list 131607fe6a43SSeth Howell * params: 131707fe6a43SSeth Howell * raid_bdev - pointer to raid bdev 131807fe6a43SSeth Howell * cb_fn - callback function 131907fe6a43SSeth Howell * cb_arg - argument to callback function 132007fe6a43SSeth Howell * returns: 132107fe6a43SSeth Howell * none 132207fe6a43SSeth Howell */ 132307fe6a43SSeth Howell static void 132407fe6a43SSeth Howell raid_bdev_deconfigure(struct raid_bdev *raid_bdev, raid_bdev_destruct_cb cb_fn, 132507fe6a43SSeth Howell void *cb_arg) 132607fe6a43SSeth Howell { 132707fe6a43SSeth Howell if (raid_bdev->state != RAID_BDEV_STATE_ONLINE) { 132807fe6a43SSeth Howell if (cb_fn) { 132907fe6a43SSeth Howell cb_fn(cb_arg, 0); 133007fe6a43SSeth Howell } 133107fe6a43SSeth Howell return; 133207fe6a43SSeth Howell } 133307fe6a43SSeth Howell 133407fe6a43SSeth Howell raid_bdev->state = RAID_BDEV_STATE_OFFLINE; 133507fe6a43SSeth Howell assert(raid_bdev->num_base_bdevs_discovered); 13361960ef16SJosh Soref SPDK_DEBUGLOG(bdev_raid, "raid bdev state changing from online to offline\n"); 133707fe6a43SSeth Howell 133807fe6a43SSeth Howell spdk_bdev_unregister(&raid_bdev->bdev, cb_fn, cb_arg); 133907fe6a43SSeth Howell } 134007fe6a43SSeth Howell 134107fe6a43SSeth Howell /* 134207fe6a43SSeth Howell * brief: 134326861b70SArtur Paszkiewicz * raid_bdev_find_base_info_by_bdev function finds the base bdev info by bdev. 134407fe6a43SSeth Howell * params: 134526861b70SArtur Paszkiewicz * base_bdev - pointer to base bdev 134607fe6a43SSeth Howell * returns: 134726861b70SArtur Paszkiewicz * base bdev info if found, otherwise NULL. 134807fe6a43SSeth Howell */ 134926861b70SArtur Paszkiewicz static struct raid_base_bdev_info * 135026861b70SArtur Paszkiewicz raid_bdev_find_base_info_by_bdev(struct spdk_bdev *base_bdev) 135107fe6a43SSeth Howell { 135207fe6a43SSeth Howell struct raid_bdev *raid_bdev; 1353a193dcb8SArtur Paszkiewicz struct raid_base_bdev_info *base_info; 135407fe6a43SSeth Howell 135507fe6a43SSeth Howell TAILQ_FOREACH(raid_bdev, &g_raid_bdev_list, global_link) { 1356a193dcb8SArtur Paszkiewicz RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) { 13578d1993a5SArtur Paszkiewicz if (base_info->desc != NULL && 13588d1993a5SArtur Paszkiewicz spdk_bdev_desc_get_bdev(base_info->desc) == base_bdev) { 135926861b70SArtur Paszkiewicz return base_info; 136007fe6a43SSeth Howell } 136107fe6a43SSeth Howell } 136207fe6a43SSeth Howell } 136307fe6a43SSeth Howell 136426861b70SArtur Paszkiewicz return NULL; 136507fe6a43SSeth Howell } 136607fe6a43SSeth Howell 1367b42cb0e5SArtur Paszkiewicz static void 1368b42cb0e5SArtur Paszkiewicz raid_bdev_remove_base_bdev_on_unquiesced(void *ctx, int status) 1369b42cb0e5SArtur Paszkiewicz { 1370b42cb0e5SArtur Paszkiewicz struct raid_base_bdev_info *base_info = ctx; 1371b42cb0e5SArtur Paszkiewicz struct raid_bdev *raid_bdev = base_info->raid_bdev; 1372b42cb0e5SArtur Paszkiewicz 1373b42cb0e5SArtur Paszkiewicz base_info->remove_scheduled = false; 1374b42cb0e5SArtur Paszkiewicz 1375b42cb0e5SArtur Paszkiewicz if (status != 0) { 1376b42cb0e5SArtur Paszkiewicz SPDK_ERRLOG("Failed to unquiesce raid bdev %s: %s\n", 1377b42cb0e5SArtur Paszkiewicz raid_bdev->bdev.name, spdk_strerror(-status)); 137823850b03SKrzysztof Smolinski goto out; 1379b42cb0e5SArtur Paszkiewicz } 1380b42cb0e5SArtur Paszkiewicz 1381b42cb0e5SArtur Paszkiewicz spdk_spin_lock(&raid_bdev->base_bdev_lock); 1382b42cb0e5SArtur Paszkiewicz raid_bdev_free_base_bdev_resource(base_info); 1383b42cb0e5SArtur Paszkiewicz spdk_spin_unlock(&raid_bdev->base_bdev_lock); 138423850b03SKrzysztof Smolinski out: 138523850b03SKrzysztof Smolinski if (base_info->remove_cb != NULL) { 138623850b03SKrzysztof Smolinski base_info->remove_cb(base_info->remove_cb_ctx, status); 138723850b03SKrzysztof Smolinski } 1388b42cb0e5SArtur Paszkiewicz } 1389b42cb0e5SArtur Paszkiewicz 1390b42cb0e5SArtur Paszkiewicz static void 1391b42cb0e5SArtur Paszkiewicz raid_bdev_channel_remove_base_bdev(struct spdk_io_channel_iter *i) 1392b42cb0e5SArtur Paszkiewicz { 1393b42cb0e5SArtur Paszkiewicz struct raid_base_bdev_info *base_info = spdk_io_channel_iter_get_ctx(i); 1394b42cb0e5SArtur Paszkiewicz struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(i); 1395b42cb0e5SArtur Paszkiewicz struct raid_bdev_io_channel *raid_ch = spdk_io_channel_get_ctx(ch); 1396b42cb0e5SArtur Paszkiewicz uint8_t idx = base_info - base_info->raid_bdev->base_bdev_info; 1397b42cb0e5SArtur Paszkiewicz 1398b42cb0e5SArtur Paszkiewicz SPDK_DEBUGLOG(bdev_raid, "slot: %u raid_ch: %p\n", idx, raid_ch); 1399b42cb0e5SArtur Paszkiewicz 1400b42cb0e5SArtur Paszkiewicz if (raid_ch->base_channel[idx] != NULL) { 1401b42cb0e5SArtur Paszkiewicz spdk_put_io_channel(raid_ch->base_channel[idx]); 1402b42cb0e5SArtur Paszkiewicz raid_ch->base_channel[idx] = NULL; 1403b42cb0e5SArtur Paszkiewicz } 1404b42cb0e5SArtur Paszkiewicz 1405b42cb0e5SArtur Paszkiewicz spdk_for_each_channel_continue(i, 0); 1406b42cb0e5SArtur Paszkiewicz } 1407b42cb0e5SArtur Paszkiewicz 1408b42cb0e5SArtur Paszkiewicz static void 1409b42cb0e5SArtur Paszkiewicz raid_bdev_channels_remove_base_bdev_done(struct spdk_io_channel_iter *i, int status) 1410b42cb0e5SArtur Paszkiewicz { 1411b42cb0e5SArtur Paszkiewicz struct raid_base_bdev_info *base_info = spdk_io_channel_iter_get_ctx(i); 1412b42cb0e5SArtur Paszkiewicz struct raid_bdev *raid_bdev = base_info->raid_bdev; 1413b42cb0e5SArtur Paszkiewicz 1414b42cb0e5SArtur Paszkiewicz spdk_bdev_unquiesce(&raid_bdev->bdev, &g_raid_if, raid_bdev_remove_base_bdev_on_unquiesced, 1415b42cb0e5SArtur Paszkiewicz base_info); 1416b42cb0e5SArtur Paszkiewicz } 1417b42cb0e5SArtur Paszkiewicz 1418b42cb0e5SArtur Paszkiewicz static void 1419b42cb0e5SArtur Paszkiewicz raid_bdev_remove_base_bdev_on_quiesced(void *ctx, int status) 1420b42cb0e5SArtur Paszkiewicz { 1421b42cb0e5SArtur Paszkiewicz struct raid_base_bdev_info *base_info = ctx; 1422b42cb0e5SArtur Paszkiewicz struct raid_bdev *raid_bdev = base_info->raid_bdev; 1423b42cb0e5SArtur Paszkiewicz 1424b42cb0e5SArtur Paszkiewicz if (status != 0) { 1425b42cb0e5SArtur Paszkiewicz SPDK_ERRLOG("Failed to quiesce raid bdev %s: %s\n", 1426b42cb0e5SArtur Paszkiewicz raid_bdev->bdev.name, spdk_strerror(-status)); 1427b42cb0e5SArtur Paszkiewicz base_info->remove_scheduled = false; 142823850b03SKrzysztof Smolinski if (base_info->remove_cb != NULL) { 142923850b03SKrzysztof Smolinski base_info->remove_cb(base_info->remove_cb_ctx, status); 143023850b03SKrzysztof Smolinski } 1431b42cb0e5SArtur Paszkiewicz return; 1432b42cb0e5SArtur Paszkiewicz } 1433b42cb0e5SArtur Paszkiewicz 1434b42cb0e5SArtur Paszkiewicz spdk_for_each_channel(raid_bdev, raid_bdev_channel_remove_base_bdev, base_info, 1435b42cb0e5SArtur Paszkiewicz raid_bdev_channels_remove_base_bdev_done); 1436b42cb0e5SArtur Paszkiewicz } 1437b42cb0e5SArtur Paszkiewicz 143807fe6a43SSeth Howell /* 143907fe6a43SSeth Howell * brief: 144007fe6a43SSeth Howell * raid_bdev_remove_base_bdev function is called by below layers when base_bdev 144107fe6a43SSeth Howell * is removed. This function checks if this base bdev is part of any raid bdev 144207fe6a43SSeth Howell * or not. If yes, it takes necessary action on that particular raid bdev. 144307fe6a43SSeth Howell * params: 1444c9224e26SShuhei Matsumoto * base_bdev - pointer to base bdev which got removed 144523850b03SKrzysztof Smolinski * cb_fn - callback function 144623850b03SKrzysztof Smolinski * cb_arg - argument to callback function 144707fe6a43SSeth Howell * returns: 1448b42cb0e5SArtur Paszkiewicz * 0 - success 1449b42cb0e5SArtur Paszkiewicz * non zero - failure 145007fe6a43SSeth Howell */ 145123850b03SKrzysztof Smolinski int 145223850b03SKrzysztof Smolinski raid_bdev_remove_base_bdev(struct spdk_bdev *base_bdev, raid_bdev_remove_base_bdev_cb cb_fn, 145323850b03SKrzysztof Smolinski void *cb_ctx) 145407fe6a43SSeth Howell { 145526861b70SArtur Paszkiewicz struct raid_bdev *raid_bdev; 1456a193dcb8SArtur Paszkiewicz struct raid_base_bdev_info *base_info; 145707fe6a43SSeth Howell 1458b42cb0e5SArtur Paszkiewicz SPDK_DEBUGLOG(bdev_raid, "%s\n", base_bdev->name); 145907fe6a43SSeth Howell 146007fe6a43SSeth Howell /* Find the raid_bdev which has claimed this base_bdev */ 146126861b70SArtur Paszkiewicz base_info = raid_bdev_find_base_info_by_bdev(base_bdev); 146226861b70SArtur Paszkiewicz if (!base_info) { 146307fe6a43SSeth Howell SPDK_ERRLOG("bdev to remove '%s' not found\n", base_bdev->name); 1464b42cb0e5SArtur Paszkiewicz return -ENODEV; 146507fe6a43SSeth Howell } 146626861b70SArtur Paszkiewicz raid_bdev = base_info->raid_bdev; 146707fe6a43SSeth Howell 14684dd2a0d3SArtur Paszkiewicz assert(spdk_get_thread() == spdk_thread_get_app_thread()); 14694dd2a0d3SArtur Paszkiewicz 1470b42cb0e5SArtur Paszkiewicz if (base_info->remove_scheduled) { 1471b42cb0e5SArtur Paszkiewicz return 0; 1472b42cb0e5SArtur Paszkiewicz } 1473b42cb0e5SArtur Paszkiewicz 1474a193dcb8SArtur Paszkiewicz assert(base_info->desc); 1475a193dcb8SArtur Paszkiewicz base_info->remove_scheduled = true; 147623850b03SKrzysztof Smolinski base_info->remove_cb = cb_fn; 147723850b03SKrzysztof Smolinski base_info->remove_cb_ctx = cb_ctx; 147807fe6a43SSeth Howell 14794ad1ac90SArtur Paszkiewicz if (raid_bdev->state != RAID_BDEV_STATE_ONLINE) { 148007fe6a43SSeth Howell /* 148107fe6a43SSeth Howell * As raid bdev is not registered yet or already unregistered, 148207fe6a43SSeth Howell * so cleanup should be done here itself. 148307fe6a43SSeth Howell */ 148426861b70SArtur Paszkiewicz raid_bdev_free_base_bdev_resource(base_info); 148507fe6a43SSeth Howell if (raid_bdev->num_base_bdevs_discovered == 0) { 148607fe6a43SSeth Howell /* There is no base bdev for this raid, so free the raid device. */ 148795a04949SArtur Paszkiewicz raid_bdev_cleanup_and_free(raid_bdev); 1488b42cb0e5SArtur Paszkiewicz } 1489b42cb0e5SArtur Paszkiewicz } else if (raid_bdev->num_base_bdevs_discovered == raid_bdev->min_base_bdevs_operational) { 1490b42cb0e5SArtur Paszkiewicz /* 1491b42cb0e5SArtur Paszkiewicz * After this base bdev is removed there will not be enough base bdevs 1492b42cb0e5SArtur Paszkiewicz * to keep the raid bdev operational. 1493b42cb0e5SArtur Paszkiewicz */ 149423850b03SKrzysztof Smolinski raid_bdev_deconfigure(raid_bdev, cb_fn, cb_ctx); 1495b42cb0e5SArtur Paszkiewicz } else { 1496b42cb0e5SArtur Paszkiewicz int ret; 1497b42cb0e5SArtur Paszkiewicz 1498b42cb0e5SArtur Paszkiewicz ret = spdk_bdev_quiesce(&raid_bdev->bdev, &g_raid_if, 1499b42cb0e5SArtur Paszkiewicz raid_bdev_remove_base_bdev_on_quiesced, base_info); 1500b42cb0e5SArtur Paszkiewicz if (ret != 0) { 1501b42cb0e5SArtur Paszkiewicz base_info->remove_scheduled = false; 150207fe6a43SSeth Howell } 150307fe6a43SSeth Howell } 150407fe6a43SSeth Howell 1505b42cb0e5SArtur Paszkiewicz return 0; 150607fe6a43SSeth Howell } 150707fe6a43SSeth Howell 150807fe6a43SSeth Howell /* 150907fe6a43SSeth Howell * brief: 1510c9224e26SShuhei Matsumoto * raid_bdev_resize_base_bdev function is called by below layers when base_bdev 1511c9224e26SShuhei Matsumoto * is resized. This function checks if the smallest size of the base_bdevs is changed. 1512c9224e26SShuhei Matsumoto * If yes, call module handler to resize the raid_bdev if implemented. 1513c9224e26SShuhei Matsumoto * params: 1514c9224e26SShuhei Matsumoto * base_bdev - pointer to base bdev which got resized. 1515c9224e26SShuhei Matsumoto * returns: 1516c9224e26SShuhei Matsumoto * none 1517c9224e26SShuhei Matsumoto */ 1518c9224e26SShuhei Matsumoto static void 1519c9224e26SShuhei Matsumoto raid_bdev_resize_base_bdev(struct spdk_bdev *base_bdev) 1520c9224e26SShuhei Matsumoto { 152126861b70SArtur Paszkiewicz struct raid_bdev *raid_bdev; 1522c9224e26SShuhei Matsumoto struct raid_base_bdev_info *base_info; 1523c9224e26SShuhei Matsumoto 1524c9224e26SShuhei Matsumoto SPDK_DEBUGLOG(bdev_raid, "raid_bdev_resize_base_bdev\n"); 1525c9224e26SShuhei Matsumoto 152626861b70SArtur Paszkiewicz base_info = raid_bdev_find_base_info_by_bdev(base_bdev); 152726861b70SArtur Paszkiewicz 1528c9224e26SShuhei Matsumoto /* Find the raid_bdev which has claimed this base_bdev */ 152926861b70SArtur Paszkiewicz if (!base_info) { 1530c9224e26SShuhei Matsumoto SPDK_ERRLOG("raid_bdev whose base_bdev '%s' not found\n", base_bdev->name); 1531c9224e26SShuhei Matsumoto return; 1532c9224e26SShuhei Matsumoto } 153326861b70SArtur Paszkiewicz raid_bdev = base_info->raid_bdev; 1534c9224e26SShuhei Matsumoto 1535c9224e26SShuhei Matsumoto assert(spdk_get_thread() == spdk_thread_get_app_thread()); 1536c9224e26SShuhei Matsumoto 1537c9224e26SShuhei Matsumoto SPDK_NOTICELOG("base_bdev '%s' was resized: old size %" PRIu64 ", new size %" PRIu64 "\n", 1538c9224e26SShuhei Matsumoto base_bdev->name, base_info->blockcnt, base_bdev->blockcnt); 1539c9224e26SShuhei Matsumoto 1540c9224e26SShuhei Matsumoto if (raid_bdev->module->resize) { 1541c9224e26SShuhei Matsumoto raid_bdev->module->resize(raid_bdev); 1542c9224e26SShuhei Matsumoto } 1543c9224e26SShuhei Matsumoto } 1544c9224e26SShuhei Matsumoto 1545c9224e26SShuhei Matsumoto /* 1546c9224e26SShuhei Matsumoto * brief: 1547d8a18924SShuhei Matsumoto * raid_bdev_event_base_bdev function is called by below layers when base_bdev 1548d8a18924SShuhei Matsumoto * triggers asynchronous event. 1549d8a18924SShuhei Matsumoto * params: 1550d8a18924SShuhei Matsumoto * type - event details. 1551d8a18924SShuhei Matsumoto * bdev - bdev that triggered event. 1552d8a18924SShuhei Matsumoto * event_ctx - context for event. 1553d8a18924SShuhei Matsumoto * returns: 1554d8a18924SShuhei Matsumoto * none 1555d8a18924SShuhei Matsumoto */ 1556d8a18924SShuhei Matsumoto static void 1557d8a18924SShuhei Matsumoto raid_bdev_event_base_bdev(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, 1558d8a18924SShuhei Matsumoto void *event_ctx) 1559d8a18924SShuhei Matsumoto { 1560b42cb0e5SArtur Paszkiewicz int rc; 1561b42cb0e5SArtur Paszkiewicz 1562d8a18924SShuhei Matsumoto switch (type) { 1563d8a18924SShuhei Matsumoto case SPDK_BDEV_EVENT_REMOVE: 156423850b03SKrzysztof Smolinski rc = raid_bdev_remove_base_bdev(bdev, NULL, NULL); 1565b42cb0e5SArtur Paszkiewicz if (rc != 0) { 1566b42cb0e5SArtur Paszkiewicz SPDK_ERRLOG("Failed to remove base bdev %s: %s\n", 1567b42cb0e5SArtur Paszkiewicz spdk_bdev_get_name(bdev), spdk_strerror(-rc)); 1568b42cb0e5SArtur Paszkiewicz } 1569d8a18924SShuhei Matsumoto break; 1570c9224e26SShuhei Matsumoto case SPDK_BDEV_EVENT_RESIZE: 1571c9224e26SShuhei Matsumoto raid_bdev_resize_base_bdev(bdev); 1572c9224e26SShuhei Matsumoto break; 1573d8a18924SShuhei Matsumoto default: 1574d8a18924SShuhei Matsumoto SPDK_NOTICELOG("Unsupported bdev event: type %d\n", type); 1575d8a18924SShuhei Matsumoto break; 1576d8a18924SShuhei Matsumoto } 1577d8a18924SShuhei Matsumoto } 1578d8a18924SShuhei Matsumoto 1579d8a18924SShuhei Matsumoto /* 1580d8a18924SShuhei Matsumoto * brief: 1581dccdd1e5SArtur Paszkiewicz * Deletes the specified raid bdev 158207fe6a43SSeth Howell * params: 1583dccdd1e5SArtur Paszkiewicz * raid_bdev - pointer to raid bdev 158407fe6a43SSeth Howell * cb_fn - callback function 1585dccdd1e5SArtur Paszkiewicz * cb_arg - argument to callback function 158607fe6a43SSeth Howell */ 158707fe6a43SSeth Howell void 1588dccdd1e5SArtur Paszkiewicz raid_bdev_delete(struct raid_bdev *raid_bdev, raid_bdev_destruct_cb cb_fn, void *cb_arg) 158907fe6a43SSeth Howell { 1590a193dcb8SArtur Paszkiewicz struct raid_base_bdev_info *base_info; 159107fe6a43SSeth Howell 1592dccdd1e5SArtur Paszkiewicz SPDK_DEBUGLOG(bdev_raid, "delete raid bdev: %s\n", raid_bdev->bdev.name); 159307fe6a43SSeth Howell 159407fe6a43SSeth Howell if (raid_bdev->destroy_started) { 15952172c432STomasz Zawadzki SPDK_DEBUGLOG(bdev_raid, "destroying raid bdev %s is already started\n", 1596dccdd1e5SArtur Paszkiewicz raid_bdev->bdev.name); 159707fe6a43SSeth Howell if (cb_fn) { 159807fe6a43SSeth Howell cb_fn(cb_arg, -EALREADY); 159907fe6a43SSeth Howell } 160007fe6a43SSeth Howell return; 160107fe6a43SSeth Howell } 160207fe6a43SSeth Howell 160307fe6a43SSeth Howell raid_bdev->destroy_started = true; 160407fe6a43SSeth Howell 1605a193dcb8SArtur Paszkiewicz RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) { 1606a193dcb8SArtur Paszkiewicz base_info->remove_scheduled = true; 160707fe6a43SSeth Howell 16084ad1ac90SArtur Paszkiewicz if (raid_bdev->state != RAID_BDEV_STATE_ONLINE) { 160907fe6a43SSeth Howell /* 161007fe6a43SSeth Howell * As raid bdev is not registered yet or already unregistered, 161107fe6a43SSeth Howell * so cleanup should be done here itself. 161207fe6a43SSeth Howell */ 161326861b70SArtur Paszkiewicz raid_bdev_free_base_bdev_resource(base_info); 1614df1e07e9SGangCao } 1615df1e07e9SGangCao } 1616df1e07e9SGangCao 161707fe6a43SSeth Howell if (raid_bdev->num_base_bdevs_discovered == 0) { 161807fe6a43SSeth Howell /* There is no base bdev for this raid, so free the raid device. */ 161995a04949SArtur Paszkiewicz raid_bdev_cleanup_and_free(raid_bdev); 162007fe6a43SSeth Howell if (cb_fn) { 162107fe6a43SSeth Howell cb_fn(cb_arg, 0); 162207fe6a43SSeth Howell } 1623df1e07e9SGangCao } else { 162407fe6a43SSeth Howell raid_bdev_deconfigure(raid_bdev, cb_fn, cb_arg); 162507fe6a43SSeth Howell } 1626df1e07e9SGangCao } 162707fe6a43SSeth Howell 16289222ff97SArtur Paszkiewicz static void 16299222ff97SArtur Paszkiewicz raid_bdev_configure_base_bdev_cont(struct raid_base_bdev_info *base_info) 16309222ff97SArtur Paszkiewicz { 16319222ff97SArtur Paszkiewicz struct raid_bdev *raid_bdev = base_info->raid_bdev; 16329222ff97SArtur Paszkiewicz int rc; 16339222ff97SArtur Paszkiewicz 16349222ff97SArtur Paszkiewicz base_info->is_configured = true; 16359222ff97SArtur Paszkiewicz 16369222ff97SArtur Paszkiewicz raid_bdev->num_base_bdevs_discovered++; 16379222ff97SArtur Paszkiewicz assert(raid_bdev->num_base_bdevs_discovered <= raid_bdev->num_base_bdevs); 16389222ff97SArtur Paszkiewicz 16399222ff97SArtur Paszkiewicz if (raid_bdev->num_base_bdevs_discovered == raid_bdev->num_base_bdevs) { 16409222ff97SArtur Paszkiewicz rc = raid_bdev_configure(raid_bdev); 16419222ff97SArtur Paszkiewicz if (rc != 0) { 16429222ff97SArtur Paszkiewicz SPDK_ERRLOG("Failed to configure raid bdev: %s\n", spdk_strerror(-rc)); 16439222ff97SArtur Paszkiewicz } 16449222ff97SArtur Paszkiewicz } 16459222ff97SArtur Paszkiewicz } 16469222ff97SArtur Paszkiewicz 16479222ff97SArtur Paszkiewicz static void 16489222ff97SArtur Paszkiewicz raid_bdev_configure_base_bdev_check_sb_cb(const struct raid_bdev_superblock *sb, int status, 16499222ff97SArtur Paszkiewicz void *ctx) 16509222ff97SArtur Paszkiewicz { 16519222ff97SArtur Paszkiewicz struct raid_base_bdev_info *base_info = ctx; 16529222ff97SArtur Paszkiewicz 16539222ff97SArtur Paszkiewicz switch (status) { 16549222ff97SArtur Paszkiewicz case 0: 16559222ff97SArtur Paszkiewicz /* valid superblock found */ 16569222ff97SArtur Paszkiewicz SPDK_ERRLOG("Existing raid superblock found on bdev %s\n", base_info->name); 16579222ff97SArtur Paszkiewicz raid_bdev_free_base_bdev_resource(base_info); 16589222ff97SArtur Paszkiewicz break; 16599222ff97SArtur Paszkiewicz case -EINVAL: 16609222ff97SArtur Paszkiewicz /* no valid superblock */ 16619222ff97SArtur Paszkiewicz raid_bdev_configure_base_bdev_cont(base_info); 16629222ff97SArtur Paszkiewicz break; 16639222ff97SArtur Paszkiewicz default: 16649222ff97SArtur Paszkiewicz SPDK_ERRLOG("Failed to examine bdev %s: %s\n", 16659222ff97SArtur Paszkiewicz base_info->name, spdk_strerror(-status)); 16669222ff97SArtur Paszkiewicz break; 16679222ff97SArtur Paszkiewicz } 16689222ff97SArtur Paszkiewicz } 16699222ff97SArtur Paszkiewicz 167007fe6a43SSeth Howell static int 16719222ff97SArtur Paszkiewicz raid_bdev_configure_base_bdev(struct raid_base_bdev_info *base_info, bool existing) 167207fe6a43SSeth Howell { 167326861b70SArtur Paszkiewicz struct raid_bdev *raid_bdev = base_info->raid_bdev; 1674dccdd1e5SArtur Paszkiewicz struct spdk_bdev_desc *desc; 1675dccdd1e5SArtur Paszkiewicz struct spdk_bdev *bdev; 16768a6bb6a8SArtur Paszkiewicz const struct spdk_uuid *bdev_uuid; 167707fe6a43SSeth Howell int rc; 167807fe6a43SSeth Howell 16794dd2a0d3SArtur Paszkiewicz assert(spdk_get_thread() == spdk_thread_get_app_thread()); 16808d1993a5SArtur Paszkiewicz assert(base_info->desc == NULL); 168107fe6a43SSeth Howell 16828a6bb6a8SArtur Paszkiewicz /* 16838a6bb6a8SArtur Paszkiewicz * Base bdev can be added by name or uuid. Here we assure both properties are set and valid 16848a6bb6a8SArtur Paszkiewicz * before claiming the bdev. 16858a6bb6a8SArtur Paszkiewicz */ 16868a6bb6a8SArtur Paszkiewicz 16878a6bb6a8SArtur Paszkiewicz if (!spdk_uuid_is_null(&base_info->uuid)) { 16888a6bb6a8SArtur Paszkiewicz char uuid_str[SPDK_UUID_STRING_LEN]; 16898a6bb6a8SArtur Paszkiewicz const char *bdev_name; 16908a6bb6a8SArtur Paszkiewicz 16918a6bb6a8SArtur Paszkiewicz spdk_uuid_fmt_lower(uuid_str, sizeof(uuid_str), &base_info->uuid); 16928a6bb6a8SArtur Paszkiewicz 16938a6bb6a8SArtur Paszkiewicz /* UUID of a bdev is registered as its alias */ 16948a6bb6a8SArtur Paszkiewicz bdev = spdk_bdev_get_by_name(uuid_str); 16958a6bb6a8SArtur Paszkiewicz if (bdev == NULL) { 16968a6bb6a8SArtur Paszkiewicz return -ENODEV; 16978a6bb6a8SArtur Paszkiewicz } 16988a6bb6a8SArtur Paszkiewicz 16998a6bb6a8SArtur Paszkiewicz bdev_name = spdk_bdev_get_name(bdev); 17008a6bb6a8SArtur Paszkiewicz 17018a6bb6a8SArtur Paszkiewicz if (base_info->name == NULL) { 17029222ff97SArtur Paszkiewicz assert(existing == true); 17038a6bb6a8SArtur Paszkiewicz base_info->name = strdup(bdev_name); 17048a6bb6a8SArtur Paszkiewicz if (base_info->name == NULL) { 17058a6bb6a8SArtur Paszkiewicz return -ENOMEM; 17068a6bb6a8SArtur Paszkiewicz } 17078a6bb6a8SArtur Paszkiewicz } else if (strcmp(base_info->name, bdev_name) != 0) { 17088a6bb6a8SArtur Paszkiewicz SPDK_ERRLOG("Name mismatch for base bdev '%s' - expected '%s'\n", 17098a6bb6a8SArtur Paszkiewicz bdev_name, base_info->name); 17108a6bb6a8SArtur Paszkiewicz return -EINVAL; 17118a6bb6a8SArtur Paszkiewicz } 17128a6bb6a8SArtur Paszkiewicz } 17138a6bb6a8SArtur Paszkiewicz 17148a6bb6a8SArtur Paszkiewicz assert(base_info->name != NULL); 17158a6bb6a8SArtur Paszkiewicz 1716dccdd1e5SArtur Paszkiewicz rc = spdk_bdev_open_ext(base_info->name, true, raid_bdev_event_base_bdev, NULL, &desc); 171707fe6a43SSeth Howell if (rc != 0) { 1718bd190d88SShuhei Matsumoto if (rc != -ENODEV) { 1719dccdd1e5SArtur Paszkiewicz SPDK_ERRLOG("Unable to create desc on bdev '%s'\n", base_info->name); 1720bd190d88SShuhei Matsumoto } 172107fe6a43SSeth Howell return rc; 172207fe6a43SSeth Howell } 172307fe6a43SSeth Howell 1724dccdd1e5SArtur Paszkiewicz bdev = spdk_bdev_desc_get_bdev(desc); 17258a6bb6a8SArtur Paszkiewicz bdev_uuid = spdk_bdev_get_uuid(bdev); 17268a6bb6a8SArtur Paszkiewicz 17278a6bb6a8SArtur Paszkiewicz if (spdk_uuid_is_null(&base_info->uuid)) { 17288a6bb6a8SArtur Paszkiewicz spdk_uuid_copy(&base_info->uuid, bdev_uuid); 17298a6bb6a8SArtur Paszkiewicz } else if (spdk_uuid_compare(&base_info->uuid, bdev_uuid) != 0) { 17308a6bb6a8SArtur Paszkiewicz SPDK_ERRLOG("UUID mismatch for base bdev '%s'\n", base_info->name); 17318a6bb6a8SArtur Paszkiewicz spdk_bdev_close(desc); 17328a6bb6a8SArtur Paszkiewicz return -EINVAL; 17338a6bb6a8SArtur Paszkiewicz } 1734dccdd1e5SArtur Paszkiewicz 1735dccdd1e5SArtur Paszkiewicz rc = spdk_bdev_module_claim_bdev(bdev, NULL, &g_raid_if); 1736dccdd1e5SArtur Paszkiewicz if (rc != 0) { 1737dccdd1e5SArtur Paszkiewicz SPDK_ERRLOG("Unable to claim this bdev as it is already claimed\n"); 1738dccdd1e5SArtur Paszkiewicz spdk_bdev_close(desc); 1739dccdd1e5SArtur Paszkiewicz return rc; 1740dccdd1e5SArtur Paszkiewicz } 1741dccdd1e5SArtur Paszkiewicz 1742dccdd1e5SArtur Paszkiewicz SPDK_DEBUGLOG(bdev_raid, "bdev %s is claimed\n", bdev->name); 1743dccdd1e5SArtur Paszkiewicz 1744dccdd1e5SArtur Paszkiewicz assert(raid_bdev->state != RAID_BDEV_STATE_ONLINE); 1745dccdd1e5SArtur Paszkiewicz 174677b8f7b6SArtur Paszkiewicz base_info->app_thread_ch = spdk_bdev_get_io_channel(desc); 174777b8f7b6SArtur Paszkiewicz if (base_info->app_thread_ch == NULL) { 174877b8f7b6SArtur Paszkiewicz SPDK_ERRLOG("Failed to get io channel\n"); 174977b8f7b6SArtur Paszkiewicz spdk_bdev_module_release_bdev(bdev); 175077b8f7b6SArtur Paszkiewicz spdk_bdev_close(desc); 175177b8f7b6SArtur Paszkiewicz return -ENOMEM; 175277b8f7b6SArtur Paszkiewicz } 175377b8f7b6SArtur Paszkiewicz 1754dccdd1e5SArtur Paszkiewicz base_info->desc = desc; 1755c9224e26SShuhei Matsumoto base_info->blockcnt = bdev->blockcnt; 175607fe6a43SSeth Howell 175777b8f7b6SArtur Paszkiewicz if (raid_bdev->sb != NULL) { 17588a6bb6a8SArtur Paszkiewicz uint64_t data_offset; 1759deed7d2fSArtur Paszkiewicz 17608a6bb6a8SArtur Paszkiewicz if (base_info->data_offset == 0) { 17618a6bb6a8SArtur Paszkiewicz assert((RAID_BDEV_MIN_DATA_OFFSET_SIZE % bdev->blocklen) == 0); 17628a6bb6a8SArtur Paszkiewicz data_offset = RAID_BDEV_MIN_DATA_OFFSET_SIZE / bdev->blocklen; 17638a6bb6a8SArtur Paszkiewicz } else { 17648a6bb6a8SArtur Paszkiewicz data_offset = base_info->data_offset; 17658a6bb6a8SArtur Paszkiewicz } 17668a6bb6a8SArtur Paszkiewicz 17678a6bb6a8SArtur Paszkiewicz if (bdev->optimal_io_boundary != 0) { 17688a6bb6a8SArtur Paszkiewicz data_offset = spdk_divide_round_up(data_offset, 1769deed7d2fSArtur Paszkiewicz bdev->optimal_io_boundary) * bdev->optimal_io_boundary; 17708a6bb6a8SArtur Paszkiewicz if (base_info->data_offset != 0 && base_info->data_offset != data_offset) { 17718a6bb6a8SArtur Paszkiewicz SPDK_WARNLOG("Data offset %lu on bdev '%s' is different than optimal value %lu\n", 17728a6bb6a8SArtur Paszkiewicz base_info->data_offset, base_info->name, data_offset); 17738a6bb6a8SArtur Paszkiewicz data_offset = base_info->data_offset; 17748a6bb6a8SArtur Paszkiewicz } 17758a6bb6a8SArtur Paszkiewicz } 17768a6bb6a8SArtur Paszkiewicz 17778a6bb6a8SArtur Paszkiewicz base_info->data_offset = data_offset; 1778deed7d2fSArtur Paszkiewicz } 1779deed7d2fSArtur Paszkiewicz 1780deed7d2fSArtur Paszkiewicz if (base_info->data_offset >= bdev->blockcnt) { 1781deed7d2fSArtur Paszkiewicz SPDK_ERRLOG("Data offset %lu exceeds base bdev capacity %lu on bdev '%s'\n", 1782deed7d2fSArtur Paszkiewicz base_info->data_offset, bdev->blockcnt, base_info->name); 17838a6bb6a8SArtur Paszkiewicz rc = -EINVAL; 17848a6bb6a8SArtur Paszkiewicz goto out; 1785deed7d2fSArtur Paszkiewicz } 1786deed7d2fSArtur Paszkiewicz 17878a6bb6a8SArtur Paszkiewicz if (base_info->data_size == 0) { 1788deed7d2fSArtur Paszkiewicz base_info->data_size = bdev->blockcnt - base_info->data_offset; 17898a6bb6a8SArtur Paszkiewicz } else if (base_info->data_offset + base_info->data_size > bdev->blockcnt) { 17908a6bb6a8SArtur Paszkiewicz SPDK_ERRLOG("Data offset and size exceeds base bdev capacity %lu on bdev '%s'\n", 17918a6bb6a8SArtur Paszkiewicz bdev->blockcnt, base_info->name); 17928a6bb6a8SArtur Paszkiewicz rc = -EINVAL; 17938a6bb6a8SArtur Paszkiewicz goto out; 1794deed7d2fSArtur Paszkiewicz } 1795deed7d2fSArtur Paszkiewicz 17969222ff97SArtur Paszkiewicz if (existing) { 17979222ff97SArtur Paszkiewicz raid_bdev_configure_base_bdev_cont(base_info); 17989222ff97SArtur Paszkiewicz } else { 17999222ff97SArtur Paszkiewicz /* check for existing superblock when using a new bdev */ 18009222ff97SArtur Paszkiewicz rc = raid_bdev_load_base_bdev_superblock(desc, base_info->app_thread_ch, 18019222ff97SArtur Paszkiewicz raid_bdev_configure_base_bdev_check_sb_cb, base_info); 18029222ff97SArtur Paszkiewicz if (rc) { 18039222ff97SArtur Paszkiewicz SPDK_ERRLOG("Failed to read bdev %s superblock: %s\n", 18049222ff97SArtur Paszkiewicz bdev->name, spdk_strerror(-rc)); 18058a6bb6a8SArtur Paszkiewicz } 18068a6bb6a8SArtur Paszkiewicz } 18078a6bb6a8SArtur Paszkiewicz out: 18088a6bb6a8SArtur Paszkiewicz if (rc != 0) { 18098a6bb6a8SArtur Paszkiewicz raid_bdev_free_base_bdev_resource(base_info); 18108a6bb6a8SArtur Paszkiewicz } 181107fe6a43SSeth Howell return rc; 181207fe6a43SSeth Howell } 181307fe6a43SSeth Howell 181407fe6a43SSeth Howell /* 181507fe6a43SSeth Howell * brief: 1816dccdd1e5SArtur Paszkiewicz * raid_bdev_add_base_device function is the actual function which either adds 1817dccdd1e5SArtur Paszkiewicz * the nvme base device to existing raid bdev or create a new raid bdev. It also claims 1818dccdd1e5SArtur Paszkiewicz * the base device and keep the open descriptor. 181907fe6a43SSeth Howell * params: 1820dccdd1e5SArtur Paszkiewicz * raid_bdev - pointer to raid bdev 1821dccdd1e5SArtur Paszkiewicz * name - name of the base bdev 1822dccdd1e5SArtur Paszkiewicz * slot - position to add base bdev 182307fe6a43SSeth Howell * returns: 1824dccdd1e5SArtur Paszkiewicz * 0 - success 1825dccdd1e5SArtur Paszkiewicz * non zero - failure 182607fe6a43SSeth Howell */ 182707fe6a43SSeth Howell int 1828dccdd1e5SArtur Paszkiewicz raid_bdev_add_base_device(struct raid_bdev *raid_bdev, const char *name, uint8_t slot) 182907fe6a43SSeth Howell { 1830dccdd1e5SArtur Paszkiewicz struct raid_base_bdev_info *base_info; 1831dccdd1e5SArtur Paszkiewicz int rc; 183207fe6a43SSeth Howell 1833dccdd1e5SArtur Paszkiewicz if (slot >= raid_bdev->num_base_bdevs) { 1834dccdd1e5SArtur Paszkiewicz return -EINVAL; 183507fe6a43SSeth Howell } 183607fe6a43SSeth Howell 1837dccdd1e5SArtur Paszkiewicz base_info = &raid_bdev->base_bdev_info[slot]; 1838dccdd1e5SArtur Paszkiewicz 1839dccdd1e5SArtur Paszkiewicz if (base_info->name != NULL) { 1840dccdd1e5SArtur Paszkiewicz SPDK_ERRLOG("Slot %u on raid bdev '%s' already assigned to bdev '%s'\n", 1841dccdd1e5SArtur Paszkiewicz slot, raid_bdev->bdev.name, base_info->name); 1842dccdd1e5SArtur Paszkiewicz return -EBUSY; 1843dccdd1e5SArtur Paszkiewicz } 1844dccdd1e5SArtur Paszkiewicz 18458a6bb6a8SArtur Paszkiewicz if (!spdk_uuid_is_null(&base_info->uuid)) { 18468a6bb6a8SArtur Paszkiewicz char uuid_str[SPDK_UUID_STRING_LEN]; 18478a6bb6a8SArtur Paszkiewicz 18488a6bb6a8SArtur Paszkiewicz spdk_uuid_fmt_lower(uuid_str, sizeof(uuid_str), &base_info->uuid); 18498a6bb6a8SArtur Paszkiewicz SPDK_ERRLOG("Slot %u on raid bdev '%s' already assigned to bdev with uuid %s\n", 18508a6bb6a8SArtur Paszkiewicz slot, raid_bdev->bdev.name, uuid_str); 18518a6bb6a8SArtur Paszkiewicz return -EBUSY; 18528a6bb6a8SArtur Paszkiewicz } 18538a6bb6a8SArtur Paszkiewicz 1854dccdd1e5SArtur Paszkiewicz base_info->name = strdup(name); 1855dccdd1e5SArtur Paszkiewicz if (base_info->name == NULL) { 1856dccdd1e5SArtur Paszkiewicz return -ENOMEM; 1857dccdd1e5SArtur Paszkiewicz } 1858dccdd1e5SArtur Paszkiewicz 18599222ff97SArtur Paszkiewicz rc = raid_bdev_configure_base_bdev(base_info, false); 1860dccdd1e5SArtur Paszkiewicz if (rc != 0) { 1861dccdd1e5SArtur Paszkiewicz if (rc != -ENODEV) { 1862dccdd1e5SArtur Paszkiewicz SPDK_ERRLOG("Failed to allocate resource for bdev '%s'\n", name); 1863dccdd1e5SArtur Paszkiewicz } 186407fe6a43SSeth Howell return rc; 186507fe6a43SSeth Howell } 186607fe6a43SSeth Howell 1867dccdd1e5SArtur Paszkiewicz return 0; 1868dccdd1e5SArtur Paszkiewicz } 1869dccdd1e5SArtur Paszkiewicz 18708a6bb6a8SArtur Paszkiewicz static int 18718a6bb6a8SArtur Paszkiewicz raid_bdev_create_from_sb(const struct raid_bdev_superblock *sb, struct raid_bdev **raid_bdev_out) 18728a6bb6a8SArtur Paszkiewicz { 18738a6bb6a8SArtur Paszkiewicz struct raid_bdev *raid_bdev; 18748a6bb6a8SArtur Paszkiewicz uint8_t i; 18758a6bb6a8SArtur Paszkiewicz int rc; 18768a6bb6a8SArtur Paszkiewicz 18778a6bb6a8SArtur Paszkiewicz rc = raid_bdev_create(sb->name, (sb->strip_size * sb->block_size) / 1024, sb->num_base_bdevs, 18788a6bb6a8SArtur Paszkiewicz sb->level, true, &sb->uuid, &raid_bdev); 18798a6bb6a8SArtur Paszkiewicz if (rc != 0) { 18808a6bb6a8SArtur Paszkiewicz return rc; 18818a6bb6a8SArtur Paszkiewicz } 18828a6bb6a8SArtur Paszkiewicz 18838a6bb6a8SArtur Paszkiewicz assert(sb->length <= RAID_BDEV_SB_MAX_LENGTH); 18848a6bb6a8SArtur Paszkiewicz memcpy(raid_bdev->sb, sb, sb->length); 18858a6bb6a8SArtur Paszkiewicz 18868a6bb6a8SArtur Paszkiewicz for (i = 0; i < sb->base_bdevs_size; i++) { 18878a6bb6a8SArtur Paszkiewicz const struct raid_bdev_sb_base_bdev *sb_base_bdev = &sb->base_bdevs[i]; 18888a6bb6a8SArtur Paszkiewicz struct raid_base_bdev_info *base_info = &raid_bdev->base_bdev_info[sb_base_bdev->slot]; 18898a6bb6a8SArtur Paszkiewicz 18908a6bb6a8SArtur Paszkiewicz if (sb_base_bdev->state == RAID_SB_BASE_BDEV_CONFIGURED) { 18918a6bb6a8SArtur Paszkiewicz spdk_uuid_copy(&base_info->uuid, &sb_base_bdev->uuid); 18928a6bb6a8SArtur Paszkiewicz } 18938a6bb6a8SArtur Paszkiewicz 18948a6bb6a8SArtur Paszkiewicz base_info->data_offset = sb_base_bdev->data_offset; 18958a6bb6a8SArtur Paszkiewicz base_info->data_size = sb_base_bdev->data_size; 18968a6bb6a8SArtur Paszkiewicz } 18978a6bb6a8SArtur Paszkiewicz 18988a6bb6a8SArtur Paszkiewicz *raid_bdev_out = raid_bdev; 18998a6bb6a8SArtur Paszkiewicz return 0; 19008a6bb6a8SArtur Paszkiewicz } 19018a6bb6a8SArtur Paszkiewicz 19028a6bb6a8SArtur Paszkiewicz static void 19038a6bb6a8SArtur Paszkiewicz raid_bdev_examine_no_sb(struct spdk_bdev *bdev) 19048a6bb6a8SArtur Paszkiewicz { 19058a6bb6a8SArtur Paszkiewicz struct raid_bdev *raid_bdev; 19068a6bb6a8SArtur Paszkiewicz struct raid_base_bdev_info *base_info; 19078a6bb6a8SArtur Paszkiewicz 19088a6bb6a8SArtur Paszkiewicz TAILQ_FOREACH(raid_bdev, &g_raid_bdev_list, global_link) { 19098a6bb6a8SArtur Paszkiewicz RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) { 19108a6bb6a8SArtur Paszkiewicz if (base_info->desc == NULL && base_info->name != NULL && 19118a6bb6a8SArtur Paszkiewicz strcmp(bdev->name, base_info->name) == 0) { 19129222ff97SArtur Paszkiewicz raid_bdev_configure_base_bdev(base_info, true); 19138a6bb6a8SArtur Paszkiewicz break; 19148a6bb6a8SArtur Paszkiewicz } 19158a6bb6a8SArtur Paszkiewicz } 19168a6bb6a8SArtur Paszkiewicz } 19178a6bb6a8SArtur Paszkiewicz } 19188a6bb6a8SArtur Paszkiewicz 19198a6bb6a8SArtur Paszkiewicz static void 19208a6bb6a8SArtur Paszkiewicz raid_bdev_examine_sb(const struct raid_bdev_superblock *sb, struct spdk_bdev *bdev) 19218a6bb6a8SArtur Paszkiewicz { 19228a6bb6a8SArtur Paszkiewicz const struct raid_bdev_sb_base_bdev *sb_base_bdev; 19238a6bb6a8SArtur Paszkiewicz struct raid_bdev *raid_bdev; 19248a6bb6a8SArtur Paszkiewicz struct raid_base_bdev_info *iter, *base_info; 19258a6bb6a8SArtur Paszkiewicz uint8_t i; 19268a6bb6a8SArtur Paszkiewicz int rc; 19278a6bb6a8SArtur Paszkiewicz 19288a6bb6a8SArtur Paszkiewicz if (sb->block_size != bdev->blocklen) { 19298a6bb6a8SArtur Paszkiewicz SPDK_WARNLOG("Bdev %s block size (%u) does not match the value in superblock (%u)\n", 19308a6bb6a8SArtur Paszkiewicz bdev->name, sb->block_size, bdev->blocklen); 19318a6bb6a8SArtur Paszkiewicz return; 19328a6bb6a8SArtur Paszkiewicz } 19338a6bb6a8SArtur Paszkiewicz 19348a6bb6a8SArtur Paszkiewicz if (spdk_uuid_is_null(&sb->uuid)) { 19358a6bb6a8SArtur Paszkiewicz SPDK_WARNLOG("NULL raid bdev UUID in superblock on bdev %s\n", bdev->name); 19368a6bb6a8SArtur Paszkiewicz return; 19378a6bb6a8SArtur Paszkiewicz } 19388a6bb6a8SArtur Paszkiewicz 19398a6bb6a8SArtur Paszkiewicz TAILQ_FOREACH(raid_bdev, &g_raid_bdev_list, global_link) { 19408a6bb6a8SArtur Paszkiewicz if (spdk_uuid_compare(&raid_bdev->bdev.uuid, &sb->uuid) == 0) { 19418a6bb6a8SArtur Paszkiewicz break; 19428a6bb6a8SArtur Paszkiewicz } 19438a6bb6a8SArtur Paszkiewicz } 19448a6bb6a8SArtur Paszkiewicz 19458a6bb6a8SArtur Paszkiewicz if (raid_bdev) { 19468a6bb6a8SArtur Paszkiewicz if (sb->seq_number > raid_bdev->sb->seq_number) { 19478a6bb6a8SArtur Paszkiewicz SPDK_DEBUGLOG(bdev_raid, 19488a6bb6a8SArtur Paszkiewicz "raid superblock seq_number on bdev %s (%lu) greater than existing raid bdev %s (%lu)\n", 19498a6bb6a8SArtur Paszkiewicz bdev->name, sb->seq_number, raid_bdev->bdev.name, raid_bdev->sb->seq_number); 19508a6bb6a8SArtur Paszkiewicz 19518a6bb6a8SArtur Paszkiewicz if (raid_bdev->state != RAID_BDEV_STATE_CONFIGURING) { 19528a6bb6a8SArtur Paszkiewicz SPDK_WARNLOG("Newer version of raid bdev %s superblock found on bdev %s but raid bdev is not in configuring state.\n", 19538a6bb6a8SArtur Paszkiewicz raid_bdev->bdev.name, bdev->name); 19548a6bb6a8SArtur Paszkiewicz return; 19558a6bb6a8SArtur Paszkiewicz } 19568a6bb6a8SArtur Paszkiewicz 19578a6bb6a8SArtur Paszkiewicz /* remove and then recreate the raid bdev using the newer superblock */ 19588a6bb6a8SArtur Paszkiewicz raid_bdev_delete(raid_bdev, NULL, NULL); 19598a6bb6a8SArtur Paszkiewicz raid_bdev = NULL; 19608a6bb6a8SArtur Paszkiewicz } else if (sb->seq_number < raid_bdev->sb->seq_number) { 19618a6bb6a8SArtur Paszkiewicz SPDK_DEBUGLOG(bdev_raid, 19628a6bb6a8SArtur Paszkiewicz "raid superblock seq_number on bdev %s (%lu) smaller than existing raid bdev %s (%lu)\n", 19638a6bb6a8SArtur Paszkiewicz bdev->name, sb->seq_number, raid_bdev->bdev.name, raid_bdev->sb->seq_number); 19648a6bb6a8SArtur Paszkiewicz /* use the current raid bdev superblock */ 19658a6bb6a8SArtur Paszkiewicz sb = raid_bdev->sb; 19668a6bb6a8SArtur Paszkiewicz } 19678a6bb6a8SArtur Paszkiewicz } 19688a6bb6a8SArtur Paszkiewicz 19698a6bb6a8SArtur Paszkiewicz for (i = 0; i < sb->base_bdevs_size; i++) { 19708a6bb6a8SArtur Paszkiewicz sb_base_bdev = &sb->base_bdevs[i]; 19718a6bb6a8SArtur Paszkiewicz 19728a6bb6a8SArtur Paszkiewicz assert(spdk_uuid_is_null(&sb_base_bdev->uuid) == false); 19738a6bb6a8SArtur Paszkiewicz 19748a6bb6a8SArtur Paszkiewicz if (spdk_uuid_compare(&sb_base_bdev->uuid, spdk_bdev_get_uuid(bdev)) == 0) { 19758a6bb6a8SArtur Paszkiewicz break; 19768a6bb6a8SArtur Paszkiewicz } 19778a6bb6a8SArtur Paszkiewicz } 19788a6bb6a8SArtur Paszkiewicz 19798a6bb6a8SArtur Paszkiewicz if (i == sb->base_bdevs_size) { 19808a6bb6a8SArtur Paszkiewicz SPDK_DEBUGLOG(bdev_raid, "raid superblock does not contain this bdev's uuid\n"); 19818a6bb6a8SArtur Paszkiewicz return; 19828a6bb6a8SArtur Paszkiewicz } 19838a6bb6a8SArtur Paszkiewicz 19848a6bb6a8SArtur Paszkiewicz if (!raid_bdev) { 19858a6bb6a8SArtur Paszkiewicz rc = raid_bdev_create_from_sb(sb, &raid_bdev); 19868a6bb6a8SArtur Paszkiewicz if (rc != 0) { 19878a6bb6a8SArtur Paszkiewicz SPDK_ERRLOG("Failed to create raid bdev %s: %s\n", 19888a6bb6a8SArtur Paszkiewicz sb->name, spdk_strerror(-rc)); 19898a6bb6a8SArtur Paszkiewicz } 19908a6bb6a8SArtur Paszkiewicz } 19918a6bb6a8SArtur Paszkiewicz 19928a6bb6a8SArtur Paszkiewicz if (sb_base_bdev->state != RAID_SB_BASE_BDEV_CONFIGURED) { 19938a6bb6a8SArtur Paszkiewicz SPDK_NOTICELOG("Bdev %s is not an active member of raid bdev %s. Ignoring.\n", 19948a6bb6a8SArtur Paszkiewicz bdev->name, raid_bdev->bdev.name); 19958a6bb6a8SArtur Paszkiewicz return; 19968a6bb6a8SArtur Paszkiewicz } 19978a6bb6a8SArtur Paszkiewicz 19988a6bb6a8SArtur Paszkiewicz base_info = NULL; 19998a6bb6a8SArtur Paszkiewicz RAID_FOR_EACH_BASE_BDEV(raid_bdev, iter) { 20008a6bb6a8SArtur Paszkiewicz if (spdk_uuid_compare(&iter->uuid, spdk_bdev_get_uuid(bdev)) == 0) { 20018a6bb6a8SArtur Paszkiewicz base_info = iter; 20028a6bb6a8SArtur Paszkiewicz break; 20038a6bb6a8SArtur Paszkiewicz } 20048a6bb6a8SArtur Paszkiewicz } 20058a6bb6a8SArtur Paszkiewicz 20068a6bb6a8SArtur Paszkiewicz if (base_info == NULL) { 20078a6bb6a8SArtur Paszkiewicz SPDK_ERRLOG("Bdev %s is not a member of raid bdev %s\n", 20088a6bb6a8SArtur Paszkiewicz bdev->name, raid_bdev->bdev.name); 20098a6bb6a8SArtur Paszkiewicz return; 20108a6bb6a8SArtur Paszkiewicz } 20118a6bb6a8SArtur Paszkiewicz 20129222ff97SArtur Paszkiewicz rc = raid_bdev_configure_base_bdev(base_info, true); 20138a6bb6a8SArtur Paszkiewicz if (rc != 0) { 20148a6bb6a8SArtur Paszkiewicz SPDK_ERRLOG("Failed to configure bdev %s as base bdev of raid %s: %s\n", 20158a6bb6a8SArtur Paszkiewicz bdev->name, raid_bdev->bdev.name, spdk_strerror(-rc)); 20168a6bb6a8SArtur Paszkiewicz } 20178a6bb6a8SArtur Paszkiewicz } 20188a6bb6a8SArtur Paszkiewicz 20198a6bb6a8SArtur Paszkiewicz struct raid_bdev_examine_ctx { 20208a6bb6a8SArtur Paszkiewicz struct spdk_bdev_desc *desc; 20218a6bb6a8SArtur Paszkiewicz struct spdk_io_channel *ch; 20228a6bb6a8SArtur Paszkiewicz }; 20238a6bb6a8SArtur Paszkiewicz 20248a6bb6a8SArtur Paszkiewicz static void 20258a6bb6a8SArtur Paszkiewicz raid_bdev_examine_ctx_free(struct raid_bdev_examine_ctx *ctx) 20268a6bb6a8SArtur Paszkiewicz { 20278a6bb6a8SArtur Paszkiewicz if (!ctx) { 20288a6bb6a8SArtur Paszkiewicz return; 20298a6bb6a8SArtur Paszkiewicz } 20308a6bb6a8SArtur Paszkiewicz 20318a6bb6a8SArtur Paszkiewicz if (ctx->ch) { 20328a6bb6a8SArtur Paszkiewicz spdk_put_io_channel(ctx->ch); 20338a6bb6a8SArtur Paszkiewicz } 20348a6bb6a8SArtur Paszkiewicz 20358a6bb6a8SArtur Paszkiewicz if (ctx->desc) { 20368a6bb6a8SArtur Paszkiewicz spdk_bdev_close(ctx->desc); 20378a6bb6a8SArtur Paszkiewicz } 20388a6bb6a8SArtur Paszkiewicz 20398a6bb6a8SArtur Paszkiewicz free(ctx); 20408a6bb6a8SArtur Paszkiewicz } 20418a6bb6a8SArtur Paszkiewicz 20428a6bb6a8SArtur Paszkiewicz static void 20438a6bb6a8SArtur Paszkiewicz raid_bdev_examine_load_sb_cb(const struct raid_bdev_superblock *sb, int status, void *_ctx) 20448a6bb6a8SArtur Paszkiewicz { 20458a6bb6a8SArtur Paszkiewicz struct raid_bdev_examine_ctx *ctx = _ctx; 20468a6bb6a8SArtur Paszkiewicz struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(ctx->desc); 20478a6bb6a8SArtur Paszkiewicz 20488a6bb6a8SArtur Paszkiewicz switch (status) { 20498a6bb6a8SArtur Paszkiewicz case 0: 20508a6bb6a8SArtur Paszkiewicz /* valid superblock found */ 20518a6bb6a8SArtur Paszkiewicz SPDK_DEBUGLOG(bdev_raid, "raid superblock found on bdev %s\n", bdev->name); 20528a6bb6a8SArtur Paszkiewicz raid_bdev_examine_sb(sb, bdev); 20538a6bb6a8SArtur Paszkiewicz break; 20548a6bb6a8SArtur Paszkiewicz case -EINVAL: 20558a6bb6a8SArtur Paszkiewicz /* no valid superblock, check if it can be claimed anyway */ 20568a6bb6a8SArtur Paszkiewicz raid_bdev_examine_no_sb(bdev); 20578a6bb6a8SArtur Paszkiewicz break; 20588a6bb6a8SArtur Paszkiewicz default: 20598a6bb6a8SArtur Paszkiewicz SPDK_ERRLOG("Failed to examine bdev %s: %s\n", 20608a6bb6a8SArtur Paszkiewicz bdev->name, spdk_strerror(-status)); 20618a6bb6a8SArtur Paszkiewicz break; 20628a6bb6a8SArtur Paszkiewicz } 20638a6bb6a8SArtur Paszkiewicz 20648a6bb6a8SArtur Paszkiewicz raid_bdev_examine_ctx_free(ctx); 20658a6bb6a8SArtur Paszkiewicz spdk_bdev_module_examine_done(&g_raid_if); 20668a6bb6a8SArtur Paszkiewicz } 20678a6bb6a8SArtur Paszkiewicz 20688a6bb6a8SArtur Paszkiewicz static void 20698a6bb6a8SArtur Paszkiewicz raid_bdev_examine_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *event_ctx) 20708a6bb6a8SArtur Paszkiewicz { 20718a6bb6a8SArtur Paszkiewicz } 20728a6bb6a8SArtur Paszkiewicz 207307fe6a43SSeth Howell /* 207407fe6a43SSeth Howell * brief: 207507fe6a43SSeth Howell * raid_bdev_examine function is the examine function call by the below layers 207607fe6a43SSeth Howell * like bdev_nvme layer. This function will check if this base bdev can be 207707fe6a43SSeth Howell * claimed by this raid bdev or not. 207807fe6a43SSeth Howell * params: 207907fe6a43SSeth Howell * bdev - pointer to base bdev 208007fe6a43SSeth Howell * returns: 208107fe6a43SSeth Howell * none 208207fe6a43SSeth Howell */ 208307fe6a43SSeth Howell static void 208407fe6a43SSeth Howell raid_bdev_examine(struct spdk_bdev *bdev) 208507fe6a43SSeth Howell { 20868a6bb6a8SArtur Paszkiewicz struct raid_bdev_examine_ctx *ctx; 20878a6bb6a8SArtur Paszkiewicz int rc; 208807fe6a43SSeth Howell 20898a6bb6a8SArtur Paszkiewicz ctx = calloc(1, sizeof(*ctx)); 20908a6bb6a8SArtur Paszkiewicz if (!ctx) { 20918a6bb6a8SArtur Paszkiewicz SPDK_ERRLOG("Failed to examine bdev %s: %s\n", 20928a6bb6a8SArtur Paszkiewicz bdev->name, spdk_strerror(ENOMEM)); 20938a6bb6a8SArtur Paszkiewicz goto err; 209407fe6a43SSeth Howell } 209507fe6a43SSeth Howell 20968a6bb6a8SArtur Paszkiewicz rc = spdk_bdev_open_ext(spdk_bdev_get_name(bdev), false, raid_bdev_examine_event_cb, NULL, 20978a6bb6a8SArtur Paszkiewicz &ctx->desc); 20988a6bb6a8SArtur Paszkiewicz if (rc) { 20998a6bb6a8SArtur Paszkiewicz SPDK_ERRLOG("Failed to open bdev %s: %s\n", 21008a6bb6a8SArtur Paszkiewicz bdev->name, spdk_strerror(-rc)); 21018a6bb6a8SArtur Paszkiewicz goto err; 21028a6bb6a8SArtur Paszkiewicz } 21038a6bb6a8SArtur Paszkiewicz 21048a6bb6a8SArtur Paszkiewicz ctx->ch = spdk_bdev_get_io_channel(ctx->desc); 21058a6bb6a8SArtur Paszkiewicz if (!ctx->ch) { 21068a6bb6a8SArtur Paszkiewicz SPDK_ERRLOG("Failed to get io channel for bdev %s\n", bdev->name); 21078a6bb6a8SArtur Paszkiewicz goto err; 21088a6bb6a8SArtur Paszkiewicz } 21098a6bb6a8SArtur Paszkiewicz 21108a6bb6a8SArtur Paszkiewicz rc = raid_bdev_load_base_bdev_superblock(ctx->desc, ctx->ch, raid_bdev_examine_load_sb_cb, ctx); 21118a6bb6a8SArtur Paszkiewicz if (rc) { 21128a6bb6a8SArtur Paszkiewicz SPDK_ERRLOG("Failed to read bdev %s superblock: %s\n", 21138a6bb6a8SArtur Paszkiewicz bdev->name, spdk_strerror(-rc)); 21148a6bb6a8SArtur Paszkiewicz goto err; 21158a6bb6a8SArtur Paszkiewicz } 21168a6bb6a8SArtur Paszkiewicz 21178a6bb6a8SArtur Paszkiewicz return; 21188a6bb6a8SArtur Paszkiewicz err: 21198a6bb6a8SArtur Paszkiewicz raid_bdev_examine_ctx_free(ctx); 212007fe6a43SSeth Howell spdk_bdev_module_examine_done(&g_raid_if); 212107fe6a43SSeth Howell } 212207fe6a43SSeth Howell 212307fe6a43SSeth Howell /* Log component for bdev raid bdev module */ 21242172c432STomasz Zawadzki SPDK_LOG_REGISTER_COMPONENT(bdev_raid) 2125