diff --git a/module/bdev/raid/bdev_raid.c b/module/bdev/raid/bdev_raid.c index 79932a600f4..47a48363530 100644 --- a/module/bdev/raid/bdev_raid.c +++ b/module/bdev/raid/bdev_raid.c @@ -221,6 +221,9 @@ raid_bdev_free_base_bdev_resource(struct raid_base_bdev_info *base_info) free(base_info->name); base_info->name = NULL; + spdk_dma_free(base_info->raid_sb); + base_info->raid_sb = NULL; + if (base_info->desc == NULL) { return; } @@ -792,6 +795,16 @@ static struct { { } }; +static bool +raid_bdev_is_raid_level(int32_t level) { + for (int i = 0; g_raid_level_names[i].name != NULL; i++) { + if (level == (int32_t) g_raid_level_names[i].value) + return true; + } + + return false; +} + /* We have to use the typedef in the function declaration to appease astyle. */ typedef enum raid_level raid_level_t; typedef enum raid_bdev_state raid_bdev_state_t; @@ -936,6 +949,59 @@ raid_bdev_init(void) return 0; } +static int +raid_bdev_module_init(struct raid_bdev *raid_bdev) { + struct raid_bdev_module *module; + uint8_t min_operational; + + module = raid_bdev_module_find(raid_bdev->level); + if (module == NULL) { + SPDK_ERRLOG("Unsupported raid_bdev level '%d'\n", raid_bdev->level); + return -EINVAL; + } + + assert(module->base_bdevs_min != 0); + if (raid_bdev->num_base_bdevs < module->base_bdevs_min) { + SPDK_ERRLOG("At least %u base devices required for %s\n", + module->base_bdevs_min, + raid_bdev_level_to_str(raid_bdev->level)); + return -EINVAL; + } + + switch (module->base_bdevs_constraint.type) { + case CONSTRAINT_MAX_BASE_BDEVS_REMOVED: + min_operational = raid_bdev->num_base_bdevs - module->base_bdevs_constraint.value; + break; + case CONSTRAINT_MIN_BASE_BDEVS_OPERATIONAL: + min_operational = module->base_bdevs_constraint.value; + break; + case CONSTRAINT_UNSET: + if (module->base_bdevs_constraint.value != 0) { + SPDK_ERRLOG("Unexpected constraint value '%u' provided for raid_bdev bdev '%s'.\n", + (uint8_t)module->base_bdevs_constraint.value, raid_bdev->bdev.name); + return -EINVAL; + } + min_operational = raid_bdev->num_base_bdevs; + break; + default: + SPDK_ERRLOG("Unrecognised constraint type '%u' in module for raid_bdev level '%s'.\n", + (uint8_t)module->base_bdevs_constraint.type, + raid_bdev_level_to_str(module->level)); + return -EINVAL; + } + + if (min_operational == 0 || min_operational > raid_bdev->num_base_bdevs) { + SPDK_ERRLOG("Wrong constraint value for raid_bdev level '%s'.\n", + raid_bdev_level_to_str(module->level)); + return -EINVAL; + } + + raid_bdev->min_base_bdevs_operational = min_operational; + raid_bdev->module = module; + + return 0; +} + /* * brief: * raid_bdev_create allocates raid bdev based on passed configuration @@ -958,9 +1024,7 @@ raid_bdev_create(const char *name, uint32_t strip_size, uint8_t num_base_bdevs, { struct raid_bdev *raid_bdev; struct spdk_bdev *raid_bdev_gen; - struct raid_bdev_module *module; struct raid_base_bdev_info *base_info; - uint8_t min_operational; if (raid_bdev_find_by_name(name) != NULL) { SPDK_ERRLOG("Duplicate raid bdev name found: %s\n", name); @@ -977,48 +1041,6 @@ raid_bdev_create(const char *name, uint32_t strip_size, uint8_t num_base_bdevs, return -EINVAL; } - module = raid_bdev_module_find(level); - if (module == NULL) { - SPDK_ERRLOG("Unsupported raid level '%d'\n", level); - return -EINVAL; - } - - assert(module->base_bdevs_min != 0); - if (num_base_bdevs < module->base_bdevs_min) { - SPDK_ERRLOG("At least %u base devices required for %s\n", - module->base_bdevs_min, - raid_bdev_level_to_str(level)); - return -EINVAL; - } - - switch (module->base_bdevs_constraint.type) { - case CONSTRAINT_MAX_BASE_BDEVS_REMOVED: - min_operational = num_base_bdevs - module->base_bdevs_constraint.value; - break; - case CONSTRAINT_MIN_BASE_BDEVS_OPERATIONAL: - min_operational = module->base_bdevs_constraint.value; - break; - case CONSTRAINT_UNSET: - if (module->base_bdevs_constraint.value != 0) { - SPDK_ERRLOG("Unexpected constraint value '%u' provided for raid bdev '%s'.\n", - (uint8_t)module->base_bdevs_constraint.value, name); - return -EINVAL; - } - min_operational = num_base_bdevs; - break; - default: - SPDK_ERRLOG("Unrecognised constraint type '%u' in module for raid level '%s'.\n", - (uint8_t)module->base_bdevs_constraint.type, - raid_bdev_level_to_str(module->level)); - return -EINVAL; - }; - - if (min_operational == 0 || min_operational > num_base_bdevs) { - SPDK_ERRLOG("Wrong constraint value for raid level '%s'.\n", - raid_bdev_level_to_str(module->level)); - return -EINVAL; - } - raid_bdev = calloc(1, sizeof(*raid_bdev)); if (!raid_bdev) { SPDK_ERRLOG("Unable to allocate memory for raid bdev\n"); @@ -1026,7 +1048,6 @@ raid_bdev_create(const char *name, uint32_t strip_size, uint8_t num_base_bdevs, } spdk_spin_init(&raid_bdev->base_bdev_lock); - raid_bdev->module = module; raid_bdev->num_base_bdevs = num_base_bdevs; raid_bdev->base_bdev_info = calloc(raid_bdev->num_base_bdevs, sizeof(struct raid_base_bdev_info)); @@ -1047,8 +1068,13 @@ raid_bdev_create(const char *name, uint32_t strip_size, uint8_t num_base_bdevs, raid_bdev->strip_size_kb = strip_size; raid_bdev->state = RAID_BDEV_STATE_CONFIGURING; raid_bdev->level = level; - raid_bdev->min_base_bdevs_operational = min_operational; raid_bdev->superblock_enabled = superblock_enabled; + raid_bdev->is_new = true; + + if (raid_bdev_module_init(raid_bdev)) { + raid_bdev_free(raid_bdev); + return -EINVAL; + } raid_bdev_gen = &raid_bdev->bdev; @@ -1116,6 +1142,258 @@ raid_bdev_configure_md(struct raid_bdev *raid_bdev) return 0; } +static void +raid_bdev_base_bdev_write_sb_compete(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg) { + struct raid_base_bdev_info *base_info = cb_arg; + + if (success) { + SPDK_DEBUGLOG(bdev_raid, "Write superblock to base bdev : '%s'\n", base_info->name); + } else { + SPDK_ERRLOG("Base bdev '%s' superblock io write has failed\n", base_info->name); + } + + spdk_bdev_free_io(bdev_io); +} + +static int +raid_bdev_base_bdev_write_sb(struct raid_base_bdev_info *base_info) +{ + int rc = 0; + struct spdk_io_channel *ch; + + ch = spdk_bdev_get_io_channel(base_info->desc); + + if (!ch) { + SPDK_ERRLOG("Unable to create io channel for bdev '%s'\n", base_info->name); + return -ENOMEM; + } + + rc = spdk_bdev_write_blocks(base_info->desc, ch, base_info->raid_sb, 0, + RAID_SB_BLOCKS(spdk_bdev_desc_get_bdev(base_info->desc)->blocklen), + (spdk_bdev_io_completion_cb) raid_bdev_base_bdev_write_sb_compete, + base_info); + + spdk_put_io_channel(ch); + return rc; +} + +static void +raid_bdev_base_bdev_read_sb_compete(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg) { + struct raid_base_bdev_info *base_info = cb_arg; + + if (success) { + SPDK_DEBUGLOG(bdev_raid, "Read superblock from base bdev : '%s'\n", base_info->name); + } else { + SPDK_ERRLOG("base bdev '%s' superblock io read has failed\n", base_info->name); + } + + spdk_bdev_free_io(bdev_io); +} + +static int +raid_bdev_base_bdev_read_sb(struct raid_base_bdev_info *base_info, uint32_t sb_size) +{ + int rc = 0; + struct spdk_io_channel *ch; + + ch = spdk_bdev_get_io_channel(base_info->desc); + + if (!ch) { + SPDK_ERRLOG("Unable to create io channel for bdev '%s'\n", base_info->name); + return -ENOMEM; + } + + rc = spdk_bdev_read_blocks(base_info->desc, ch, base_info->raid_sb, 0, + sb_size, (spdk_bdev_io_completion_cb) raid_bdev_base_bdev_read_sb_compete, + base_info); +// wait(NULL); + spdk_put_io_channel(ch); + return rc; +} + +static int +raid_bdev_base_bdev_super_load(struct raid_base_bdev_info *base_info, struct raid_base_bdev_info **freshest) +{ + int rc = 0; + struct spdk_bdev *base_bdev = spdk_bdev_desc_get_bdev(base_info->desc); + + base_info->raid_sb = spdk_dma_malloc(RAID_SB_BLOCKS(base_bdev->blocklen) * base_bdev->blocklen, 0, NULL); + if (!base_info->raid_sb) { + SPDK_ERRLOG("Failed to allocate memory for raid_sb\n"); + return -ENOMEM; + } + + rc = raid_bdev_base_bdev_read_sb(base_info, RAID_SB_BLOCKS(base_bdev->blocklen)); + if (rc) { + SPDK_ERRLOG("Failed while read superblock from base bdev '%s'\n", base_info->name); + return rc; + } + + struct raid_superblock *sb = base_info->raid_sb; + + if (sb->magic != RAID_SUPERBLOCK_MAGIC) + base_info->is_new = true; + + if (base_info->is_new) { + *freshest = *freshest ? : base_info; + return 0; + } + + if (!*freshest) { + *freshest = base_info; + return 0; + } + + if ((*freshest)->raid_sb->timestamp.tv_sec <= sb->timestamp.tv_sec && + (*freshest)->raid_sb->timestamp.tv_nsec < sb->timestamp.tv_nsec) + *freshest = base_info; + + return 0; +} + +static int +raid_bdev_super_init_validation(struct raid_bdev *raid, struct raid_base_bdev_info *base_info) +{ + struct raid_superblock *sb = base_info->raid_sb; + + assert(raid->num_base_bdevs == raid->num_base_bdevs_discovered); + + if (base_info->is_new) { + SPDK_ERRLOG("There isn't any metadata on base bdevs for raid '%s'\n", raid->bdev.name); + return -EINVAL; + } + + if (sb->version != RAID_METADATA_VERSION_01) { + SPDK_ERRLOG("Unsupported version of raid metadata has been found in base '%s' bdev's superblock\n", + base_info->name); + return -EINVAL; + } + + if (sb->num_base_bdevs != raid->num_base_bdevs) { + SPDK_ERRLOG("The '%s' bdev's number of devices isn't equal to RAID's\n", + base_info->name); + return -EINVAL; + } + + if (!raid_bdev_is_raid_level(sb->level)) { + SPDK_ERRLOG("Invalid RAID level in base '%s' bdev's metadata. Retrieving of array isn't possible\n", + base_info->name); + return -EINVAL; + } + + raid->num_base_bdevs = sb->num_base_bdevs; + raid->num_base_bdevs_discovered = sb->num_base_bdevs; + raid->level = sb->level; + raid->bdev.blocklen = sb->blocklen; + raid->bdev.blockcnt = sb->raid_blockcnt; + spdk_uuid_copy(&raid->bdev.uuid, &sb->uuid); + raid->strip_size = sb->strip_size; + raid->strip_size_kb = sb->strip_size * sb->blocklen; + raid->strip_size_shift = spdk_u32log2(sb->strip_size); + raid->blocklen_shift = spdk_u32log2(sb->blocklen); + + raid->is_new = false; + + return 0; +} + +static int +raid_bdev_base_bdev_super_sync(struct raid_base_bdev_info *base_info) +{ + struct raid_superblock *sb = base_info->raid_sb; + struct spdk_bdev *base_bdev = spdk_bdev_desc_get_bdev(base_info->desc); + struct raid_bdev *raid = base_info->raid_bdev; + + sb->magic = RAID_SUPERBLOCK_MAGIC; + sb->version = RAID_METADATA_VERSION_01; + sb->blocklen = raid->bdev.blocklen; + sb->num_base_bdevs = raid->num_base_bdevs; + sb->level = raid->level; + sb->array_position = base_info->position; + sb->strip_size = raid->strip_size; + sb->raid_blockcnt = raid->bdev.blockcnt; + spdk_uuid_copy(&sb->uuid, &raid->bdev.uuid); + + memset(sb+1, 0, RAID_SB_BLOCKS(base_bdev->blocklen)); + + return 0; +} + +static int +raid_bdev_base_bdev_capture_super_validate(struct raid_base_bdev_info *base_info) { + struct raid_superblock *sb = base_info->raid_sb; + struct raid_bdev *raid = base_info->raid_bdev; + + /* The absence of a rebuild does not allow to capture not SPDK RAID disks or disks from the another RAID now. + * Redo when the rebuild will be done. + */ + if (base_info->is_new) { + SPDK_ERRLOG("The bdev '%s' haven't been in a SPDK RAID\n", + base_info->name); + return -EINVAL; + } else if (spdk_uuid_compare(&sb->uuid, &raid->bdev.uuid)) { + SPDK_ERRLOG("The bdev '%s' have been in another RAID bdev\n", + base_info->name); + return -EINVAL; + } + + if (sb->array_position != base_info->position) { + SPDK_WARNLOG("The base bdev '%s' has changed position in the raid from '%n' to '%n'\n", base_info->name, + &sb->array_position, &base_info->position); + } + + if (sb->blocklen != raid->bdev.blocklen) { + SPDK_ERRLOG("The logical block length stored in metadata of base '%s' bdev differ from RAID block length\n", + base_info->name); + return -EINVAL; + } + + if (sb->strip_size != raid->strip_size) { + SPDK_WARNLOG("The strip size stored in metadata of base '%s' bdev differ from RAID strip size and" + "it will be overwritten\n", base_info->name); + } + + return 0; +} + +static int +raid_bdev_base_bdev_super_init(struct raid_base_bdev_info *base_info) { + struct raid_superblock *sb = base_info->raid_sb; + struct spdk_bdev *base_bdev = spdk_bdev_desc_get_bdev(base_info->desc); + struct timespec time_0 = {.tv_nsec = 0, .tv_sec = 0}; + + sb->blockcnt = base_bdev->blockcnt; + sb->timestamp = time_0; + + return 0; +} + +static int +raid_bdev_base_bdev_super_validate(struct raid_base_bdev_info *base_info, bool recreate) +{ + int rc = 0; + struct raid_superblock *sb = base_info->raid_sb; + struct raid_bdev *raid = base_info->raid_bdev; + + if (raid->num_base_bdevs <= 0 || !sb) + return 0; + + if (!recreate && raid->is_new && raid_bdev_super_init_validation(raid, base_info)) + return -EINVAL; + + if (!raid->is_new || recreate) { + if (!recreate && raid_bdev_base_bdev_capture_super_validate(base_info)) + return -EINVAL; + + raid_bdev_base_bdev_super_sync(base_info); + + if (recreate) + raid_bdev_base_bdev_super_init(base_info); + } + + return rc; +} + /* * brief: * If raid bdev config is complete, then only register the raid bdev to @@ -1134,6 +1412,8 @@ raid_bdev_configure(struct raid_bdev *raid_bdev) struct spdk_bdev *raid_bdev_gen; struct raid_base_bdev_info *base_info; struct spdk_bdev *base_bdev; + bool sb_recreate = raid_bdev->is_new; + struct raid_base_bdev_info *freshest = NULL; int rc = 0; assert(raid_bdev->state == RAID_BDEV_STATE_CONFIGURING); @@ -1176,6 +1456,35 @@ raid_bdev_configure(struct raid_bdev *raid_bdev) return rc; } + if (raid_bdev->superblock_enabled) { + RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) { + rc = raid_bdev_base_bdev_super_load(base_info, &freshest); + if (rc) { + SPDK_DEBUGLOG(bdev_raid, "super_load for base bdev has failed'%s'\n", base_info->name); + return rc; + } + } + + SPDK_DEBUGLOG(bdev_raid, "The freshest bdev is '%s'\n", freshest->name); + + if (!freshest) { + SPDK_ERRLOG("There aren't base bdevs in raid bdev '%s'\n", raid_bdev->bdev.name); + return -EINVAL; + } + + raid_bdev->is_new = true; + + rc = raid_bdev_base_bdev_super_validate(freshest, sb_recreate); + if (rc) { + SPDK_DEBUGLOG(bdev_raid, "super_validate for freshest '%s' bdev has failed\n", base_info->name); + return rc; + } + + if (!sb_recreate && raid_bdev_module_init(raid_bdev)) { + return -EINVAL; + } + } + rc = raid_bdev->module->start(raid_bdev); if (rc != 0) { SPDK_ERRLOG("raid module startup callback failed\n"); @@ -1202,6 +1511,23 @@ raid_bdev_configure(struct raid_bdev *raid_bdev) SPDK_DEBUGLOG(bdev_raid, "raid bdev is created with name %s, raid_bdev %p\n", raid_bdev_gen->name, raid_bdev); + if (raid_bdev->superblock_enabled) { + RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) { + raid_bdev_base_bdev_super_validate(base_info, sb_recreate); + if (rc) { + SPDK_DEBUGLOG(bdev_raid, "super_validate for '%s' bdev has failed\n", base_info->name); + return rc; + } + } + + RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) { + rc = raid_bdev_base_bdev_write_sb(base_info); + if (rc) { + SPDK_DEBUGLOG(bdev_raid, "Write superblock to '%s' bdev has failed\n", base_info->name); + } + } + } + return 0; } @@ -1564,7 +1890,8 @@ raid_bdev_configure_base_bdev(struct raid_base_bdev_info *base_info) if (raid_bdev->superblock_enabled) { assert((RAID_BDEV_MIN_DATA_OFFSET_SIZE % bdev->blocklen) == 0); - base_info->data_offset = RAID_BDEV_MIN_DATA_OFFSET_SIZE / bdev->blocklen; + base_info->data_offset = spdk_max(RAID_BDEV_MIN_DATA_OFFSET_SIZE/bdev->blocklen, + RAID_SB_BLOCKS(bdev->blocklen)); if (bdev->optimal_io_boundary) { base_info->data_offset = spdk_divide_round_up(base_info->data_offset, @@ -1573,7 +1900,7 @@ raid_bdev_configure_base_bdev(struct raid_base_bdev_info *base_info) if (base_info->data_offset >= bdev->blockcnt) { SPDK_ERRLOG("Data offset %lu exceeds base bdev capacity %lu on bdev '%s'\n", - base_info->data_offset, bdev->blockcnt, base_info->name); + base_info->data_offset, bdev->blockcnt, base_info->name); return -EINVAL; } diff --git a/module/bdev/raid/bdev_raid.h b/module/bdev/raid/bdev_raid.h index bd894ceef8c..f905db03f02 100644 --- a/module/bdev/raid/bdev_raid.h +++ b/module/bdev/raid/bdev_raid.h @@ -11,6 +11,10 @@ #define RAID_BDEV_MIN_DATA_OFFSET_SIZE (1024*1024) /* 1 MiB */ +#define RAID_SUPERBLOCK_MAGIC 0x534B5244 /* "SKRD" */ + +#define RAID_SB_BLOCKS(bdev_blocklen) spdk_divide_round_up(sizeof(struct raid_superblock), bdev_blocklen) + enum raid_level { INVALID_RAID_LEVEL = -1, RAID0 = 0, @@ -45,6 +49,51 @@ enum raid_bdev_state { typedef void (*raid_bdev_remove_base_bdev_cb)(void *ctx, int status); +enum metadata_version { + RAID_METADATA_VERSION_01 = 01 +}; + +#pragma pack(push, 1) +/* + * Superblock for operation with metadata of the base bdev which part of some raid. + * It stores some metadata of the base bdev and the raid + */ +struct raid_superblock { + /* SPDK raid magic number "SKRD" */ + uint32_t magic; + + /* The version of metadata. Currently, only 01 version exists */ + uint32_t version; + + /* Logical block size of base bdev */ + uint32_t blocklen; + + /* Number of base bdevs */ + uint8_t num_base_bdevs; + + /* Raid Level of device's raid */ + int32_t level; + + /* Position of device in raid */ + uint32_t array_position; + + /* strip size of device's raid in blocks */ + uint32_t strip_size; + + /* Number of blocks held by this base bdev */ + uint64_t blockcnt; + + /* Number of blocks held by device's raid */ + uint64_t raid_blockcnt; + + /* Timestamp to know the freshest device in raid */ + struct timespec timestamp; + + /* UUID of raid bdev */ + struct spdk_uuid uuid; +}; +#pragma pack(pop) + /* * raid_base_bdev_info contains information for the base bdevs which are part of some * raid. This structure contains the per base bdev information. Whatever is @@ -60,6 +109,15 @@ struct raid_base_bdev_info { /* pointer to base bdev descriptor opened by raid bdev */ struct spdk_bdev_desc *desc; + /* position of the base bdev in raid_bdev's base_bdev_info (slot) */ + uint32_t position; + + /* indicate if the metadata was on disk or not */ + bool is_new; + + /* base bdev's superblock */ + struct raid_superblock *raid_sb; + /* offset in blocks from the start of the base bdev to the start of the data region */ uint64_t data_offset; @@ -139,6 +197,9 @@ struct raid_bdev { /* state of raid bdev */ enum raid_bdev_state state; + /* indicate if raid is new for */ + bool is_new; + /* number of base bdevs comprising raid bdev */ uint8_t num_base_bdevs; diff --git a/module/bdev/raid/bdev_raid_rpc.c b/module/bdev/raid/bdev_raid_rpc.c index e108d2f856a..2421c7fe5f9 100644 --- a/module/bdev/raid/bdev_raid_rpc.c +++ b/module/bdev/raid/bdev_raid_rpc.c @@ -133,6 +133,9 @@ struct rpc_bdev_raid_create { /* If set, information about raid bdev will be stored in superblock on each base bdev */ bool superblock_enabled; + + /* If set, it tries to retrieve raid array from the base bdevs and fail if it can't */ + bool retrieve; }; /* @@ -199,6 +202,7 @@ static const struct spdk_json_object_decoder rpc_bdev_raid_create_decoders[] = { {"base_bdevs", offsetof(struct rpc_bdev_raid_create, base_bdevs), decode_base_bdevs}, {"uuid", offsetof(struct rpc_bdev_raid_create, uuid), spdk_json_decode_uuid, true}, {"superblock", offsetof(struct rpc_bdev_raid_create, superblock_enabled), spdk_json_decode_bool, true}, + {"retrieve", offsetof(struct rpc_bdev_raid_create, retrieve), spdk_json_decode_bool, true} }; /* @@ -228,6 +232,13 @@ rpc_bdev_raid_create(struct spdk_jsonrpc_request *request, goto cleanup; } + if (!req.superblock_enabled && req.retrieve) { + spdk_jsonrpc_send_error_response_fmt(request, -EINVAL, + "Retrieve option can be only if superblock is specified: %s", + spdk_strerror(-EINVAL)); + goto cleanup; + } + rc = raid_bdev_create(req.name, req.strip_size_kb, req.base_bdevs.num_base_bdevs, req.level, req.superblock_enabled, &req.uuid, &raid_bdev); if (rc != 0) { @@ -237,6 +248,10 @@ rpc_bdev_raid_create(struct spdk_jsonrpc_request *request, goto cleanup; } + if (req.retrieve) { + raid_bdev->is_new = false; + } + for (i = 0; i < req.base_bdevs.num_base_bdevs; i++) { const char *base_bdev_name = req.base_bdevs.base_bdevs[i]; diff --git a/python/spdk/rpc/bdev.py b/python/spdk/rpc/bdev.py index 25fd6f83042..8cf25dacbed 100644 --- a/python/spdk/rpc/bdev.py +++ b/python/spdk/rpc/bdev.py @@ -402,7 +402,8 @@ def bdev_raid_get_bdevs(client, category): return client.call('bdev_raid_get_bdevs', params) -def bdev_raid_create(client, name, raid_level, base_bdevs, strip_size=None, strip_size_kb=None, uuid=None, superblock=False): +def bdev_raid_create(client, name, raid_level, base_bdevs, strip_size=None, strip_size_kb=None, uuid=None, superblock=False, + retrieve=False): """Create raid bdev. Either strip size arg will work but one is required. Args: @@ -414,11 +415,12 @@ def bdev_raid_create(client, name, raid_level, base_bdevs, strip_size=None, stri uuid: UUID for this raid bdev (optional) superblock: information about raid bdev will be stored in superblock on each base bdev, disabled by default due to backward compatibility + retrieve: if specified, try to retrieve raid from superblock in base bdevs Returns: None """ - params = {'name': name, 'raid_level': raid_level, 'base_bdevs': base_bdevs, 'superblock': superblock} + params = {'name': name, 'raid_level': raid_level, 'base_bdevs': base_bdevs, 'superblock': superblock, 'retrieve': retrieve} if strip_size: params['strip_size'] = strip_size @@ -432,6 +434,22 @@ def bdev_raid_create(client, name, raid_level, base_bdevs, strip_size=None, stri return client.call('bdev_raid_create', params) +def bdev_raid_retrieve(client, name, base_bdevs): + """Wrapper of bdev_raid_create. Tried to retrieve raid array from base bdevs. + + Args: + name: user defined raid bdev name for retrieved raid + base_bdevs: Space separated names of retrieving array base bdevs in double quotes, + like "Nvme0n1 Nvme1n1 Nvme2n1" + + Returns: + None + """ + params = {'name': name, 'raid_level': 'raid1', 'base_bdevs': base_bdevs, 'superblock': True, 'retrieve': True} + + return client.call('bdev_raid_create', params) + + def bdev_raid_delete(client, name): """Delete raid bdev diff --git a/scripts/rpc.py b/scripts/rpc.py index 1ce9a8e6af0..00ee5019579 100755 --- a/scripts/rpc.py +++ b/scripts/rpc.py @@ -2130,7 +2130,8 @@ def bdev_raid_create(args): raid_level=args.raid_level, base_bdevs=base_bdevs, uuid=args.uuid, - superblock=args.superblock) + superblock=args.superblock, + retrieve=args.retrieve) p = subparsers.add_parser('bdev_raid_create', help='Create new raid bdev') p.add_argument('-n', '--name', help='raid bdev name', required=True) p.add_argument('-z', '--strip-size-kb', help='strip size in KB', type=int) @@ -2139,8 +2140,24 @@ def bdev_raid_create(args): p.add_argument('--uuid', help='UUID for this raid bdev', required=False) p.add_argument('-s', '--superblock', help='information about raid bdev will be stored in superblock on each base bdev, ' 'disabled by default due to backward compatibility', action='store_true') + p.add_argument('--retrieve', help='try to recreate raid from the superblock on the base bdevs, it only works if superblock' + 'option is specified', action='store_true') p.set_defaults(func=bdev_raid_create) + def bdev_raid_retrieve(args): + base_bdevs = [] + for u in args.base_bdevs.strip().split(" "): + base_bdevs.append(u) + + rpc.bdev.bdev_raid_retrieve(args.client, + name=args.name, + base_bdevs=base_bdevs) + p = subparsers.add_parser('bdev_raid_retrieve', help='Try to restore the raid from metadata on the base bdevs') + p.add_argument('-n', '--name', help='new name for the retrieved raid', required=True) + p.add_argument('-b', '--base-bdevs', help='name of the base bdevs which have the superblock with raid metadata, ' + 'whitespace separated list in quotes', required=True) + p.set_defaults(func=bdev_raid_retrieve) + def bdev_raid_delete(args): rpc.bdev.bdev_raid_delete(args.client, name=args.name)