Change the bdev_raid examine procedure to read the superblock from the examined base bdev. If a valid superblock is found, re-create the raid_bdev from it. Change-Id: I4bd589647a207a216ecf0dec9baf11c5d691f5d5 Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com>
230 lines
5.3 KiB
C
230 lines
5.3 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause
|
|
* Copyright (C) 2022 Intel Corporation.
|
|
* All rights reserved.
|
|
*/
|
|
|
|
#include "spdk/bdev_module.h"
|
|
#include "spdk/crc32.h"
|
|
#include "spdk/env.h"
|
|
#include "spdk/log.h"
|
|
#include "spdk/string.h"
|
|
#include "spdk/util.h"
|
|
|
|
#include "bdev_raid_sb.h"
|
|
|
|
struct raid_bdev_read_sb_ctx {
|
|
struct spdk_bdev_desc *desc;
|
|
struct spdk_io_channel *ch;
|
|
raid_bdev_load_sb_cb cb;
|
|
void *cb_ctx;
|
|
void *buf;
|
|
uint32_t buf_size;
|
|
};
|
|
|
|
struct raid_bdev_save_sb_ctx {
|
|
raid_bdev_save_sb_cb cb;
|
|
void *cb_ctx;
|
|
};
|
|
|
|
static void raid_bdev_read_sb_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg);
|
|
|
|
static int
|
|
raid_bdev_parse_superblock(struct raid_bdev_read_sb_ctx *ctx)
|
|
{
|
|
struct raid_bdev_superblock *sb = ctx->buf;
|
|
struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(ctx->desc);
|
|
uint32_t crc;
|
|
|
|
if (memcmp(sb->signature, RAID_BDEV_SB_SIG, sizeof(sb->signature))) {
|
|
SPDK_DEBUGLOG(bdev_raid_sb, "invalid signature\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (sb->length > ctx->buf_size) {
|
|
if (sb->length > RAID_BDEV_SB_MAX_LENGTH) {
|
|
SPDK_DEBUGLOG(bdev_raid_sb, "invalid length\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return -EAGAIN;
|
|
}
|
|
|
|
crc = sb->crc;
|
|
raid_bdev_sb_update_crc(sb);
|
|
if (sb->crc != crc) {
|
|
SPDK_WARNLOG("Incorrect superblock crc on bdev %s\n", spdk_bdev_get_name(bdev));
|
|
sb->crc = crc;
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (sb->version.major > RAID_BDEV_SB_VERSION_MAJOR) {
|
|
SPDK_ERRLOG("Not supported superblock major version %d on bdev %s\n",
|
|
sb->version.major, spdk_bdev_get_name(bdev));
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (sb->version.major == RAID_BDEV_SB_VERSION_MAJOR &&
|
|
sb->version.minor > RAID_BDEV_SB_VERSION_MINOR) {
|
|
SPDK_WARNLOG("Superblock minor version %d on bdev %s is higher than the currently supported: %d\n",
|
|
sb->version.minor, spdk_bdev_get_name(bdev), RAID_BDEV_SB_VERSION_MINOR);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
raid_bdev_read_sb_ctx_free(struct raid_bdev_read_sb_ctx *ctx)
|
|
{
|
|
spdk_dma_free(ctx->buf);
|
|
|
|
free(ctx);
|
|
}
|
|
|
|
static int
|
|
raid_bdev_read_sb_remainder(struct raid_bdev_read_sb_ctx *ctx)
|
|
{
|
|
struct raid_bdev_superblock *sb = ctx->buf;
|
|
struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(ctx->desc);
|
|
uint32_t buf_size_prev;
|
|
void *buf;
|
|
int rc;
|
|
|
|
buf_size_prev = ctx->buf_size;
|
|
ctx->buf_size = SPDK_ALIGN_CEIL(sb->length, spdk_bdev_get_block_size(bdev));
|
|
buf = spdk_dma_realloc(ctx->buf, ctx->buf_size, spdk_bdev_get_buf_align(bdev), NULL);
|
|
if (buf == NULL) {
|
|
SPDK_ERRLOG("Failed to reallocate buffer\n");
|
|
return -ENOMEM;
|
|
}
|
|
ctx->buf = buf;
|
|
|
|
rc = spdk_bdev_read(ctx->desc, ctx->ch, ctx->buf + buf_size_prev, buf_size_prev,
|
|
ctx->buf_size - buf_size_prev, raid_bdev_read_sb_cb, ctx);
|
|
if (rc != 0) {
|
|
SPDK_ERRLOG("Failed to read bdev %s superblock remainder: %s\n",
|
|
spdk_bdev_get_name(bdev), spdk_strerror(-rc));
|
|
return rc;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
raid_bdev_read_sb_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
|
|
{
|
|
struct raid_bdev_read_sb_ctx *ctx = cb_arg;
|
|
struct raid_bdev_superblock *sb = NULL;
|
|
int status;
|
|
|
|
spdk_bdev_free_io(bdev_io);
|
|
|
|
if (success) {
|
|
status = raid_bdev_parse_superblock(ctx);
|
|
if (status == -EAGAIN) {
|
|
status = raid_bdev_read_sb_remainder(ctx);
|
|
if (status == 0) {
|
|
return;
|
|
}
|
|
} else if (status != 0) {
|
|
SPDK_DEBUGLOG(bdev_raid_sb, "failed to parse bdev %s superblock\n",
|
|
spdk_bdev_get_name(spdk_bdev_desc_get_bdev(ctx->desc)));
|
|
} else {
|
|
sb = ctx->buf;
|
|
}
|
|
} else {
|
|
status = -EIO;
|
|
}
|
|
|
|
if (ctx->cb) {
|
|
ctx->cb(sb, status, ctx->cb_ctx);
|
|
}
|
|
|
|
raid_bdev_read_sb_ctx_free(ctx);
|
|
}
|
|
|
|
int
|
|
raid_bdev_load_base_bdev_superblock(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
|
|
raid_bdev_load_sb_cb cb, void *cb_ctx)
|
|
{
|
|
struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(desc);
|
|
struct raid_bdev_read_sb_ctx *ctx;
|
|
int rc;
|
|
|
|
ctx = calloc(1, sizeof(*ctx));
|
|
if (!ctx) {
|
|
return -ENOMEM;
|
|
}
|
|
|
|
ctx->desc = desc;
|
|
ctx->ch = ch;
|
|
ctx->cb = cb;
|
|
ctx->cb_ctx = cb_ctx;
|
|
ctx->buf_size = SPDK_ALIGN_CEIL(sizeof(struct raid_bdev_superblock),
|
|
spdk_bdev_get_block_size(bdev));
|
|
ctx->buf = spdk_dma_malloc(ctx->buf_size, spdk_bdev_get_buf_align(bdev), NULL);
|
|
if (!ctx->buf) {
|
|
rc = -ENOMEM;
|
|
goto err;
|
|
}
|
|
|
|
rc = spdk_bdev_read(desc, ch, ctx->buf, 0, ctx->buf_size, raid_bdev_read_sb_cb, ctx);
|
|
if (rc) {
|
|
goto err;
|
|
}
|
|
|
|
return 0;
|
|
err:
|
|
raid_bdev_read_sb_ctx_free(ctx);
|
|
|
|
return rc;
|
|
}
|
|
|
|
static void
|
|
raid_bdev_write_sb_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
|
|
{
|
|
struct raid_bdev_save_sb_ctx *ctx = cb_arg;
|
|
|
|
spdk_bdev_free_io(bdev_io);
|
|
|
|
if (ctx->cb) {
|
|
ctx->cb(success ? 0 : -EIO, ctx->cb_ctx);
|
|
}
|
|
|
|
free(ctx);
|
|
}
|
|
|
|
int
|
|
raid_bdev_save_base_bdev_superblock(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
|
|
const struct raid_bdev_superblock *sb,
|
|
raid_bdev_save_sb_cb cb, void *cb_ctx)
|
|
{
|
|
struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(desc);
|
|
uint64_t nbytes = SPDK_ALIGN_CEIL(sb->length, spdk_bdev_get_block_size(bdev));
|
|
struct raid_bdev_save_sb_ctx *ctx;
|
|
int rc;
|
|
|
|
ctx = calloc(1, sizeof(*ctx));
|
|
if (!ctx) {
|
|
return -ENOMEM;
|
|
}
|
|
|
|
ctx->cb = cb;
|
|
ctx->cb_ctx = cb_ctx;
|
|
|
|
rc = spdk_bdev_write(desc, ch, (void *)sb, 0, nbytes, raid_bdev_write_sb_cb, ctx);
|
|
if (rc) {
|
|
free(ctx);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
void
|
|
raid_bdev_sb_update_crc(struct raid_bdev_superblock *sb)
|
|
{
|
|
sb->crc = 0;
|
|
sb->crc = spdk_crc32c_update(sb, sb->length, 0);
|
|
}
|
|
|
|
SPDK_LOG_REGISTER_COMPONENT(bdev_raid_sb)
|