Spdk/module/bdev/raid/raid1.c
Krzysztof Smolinski 8c591e2d4f module/raid: data offset and data size implementation
When raid bdev is created with superblock parameter then all data on
this bdev should be shifted by some offset. Such space at the beginning
of bdev will be used to store on-disk raid metadata.

Signed-off-by: Krzysztof Smolinski <krzysztof.smolinski@intel.com>
Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com>
Change-Id: I2545a2b00a651ef5332ca1757da0110a63914a43
2023-05-09 17:58:11 +08:00

204 lines
5.1 KiB
C

/* SPDX-License-Identifier: BSD-3-Clause
* Copyright (C) 2022 Intel Corporation.
* All rights reserved.
*/
#include "bdev_raid.h"
#include "spdk/likely.h"
#include "spdk/log.h"
struct raid1_info {
/* The parent raid bdev */
struct raid_bdev *raid_bdev;
};
static void
raid1_bdev_io_completion(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
{
struct raid_bdev_io *raid_io = cb_arg;
spdk_bdev_free_io(bdev_io);
raid_bdev_io_complete_part(raid_io, 1, success ?
SPDK_BDEV_IO_STATUS_SUCCESS :
SPDK_BDEV_IO_STATUS_FAILED);
}
static void raid1_submit_rw_request(struct raid_bdev_io *raid_io);
static void
_raid1_submit_rw_request(void *_raid_io)
{
struct raid_bdev_io *raid_io = _raid_io;
raid1_submit_rw_request(raid_io);
}
static void
raid1_init_ext_io_opts(struct spdk_bdev_io *bdev_io, struct spdk_bdev_ext_io_opts *opts)
{
memset(opts, 0, sizeof(*opts));
opts->size = sizeof(*opts);
opts->memory_domain = bdev_io->u.bdev.memory_domain;
opts->memory_domain_ctx = bdev_io->u.bdev.memory_domain_ctx;
opts->metadata = bdev_io->u.bdev.md_buf;
}
static int
raid1_submit_read_request(struct raid_bdev_io *raid_io)
{
struct raid_bdev *raid_bdev = raid_io->raid_bdev;
struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(raid_io);
struct spdk_bdev_ext_io_opts io_opts;
uint8_t ch_idx = 0;
struct raid_base_bdev_info *base_info = &raid_bdev->base_bdev_info[ch_idx];
struct spdk_io_channel *base_ch = raid_io->raid_ch->base_channel[ch_idx];
uint64_t pd_lba, pd_blocks;
int ret;
pd_lba = bdev_io->u.bdev.offset_blocks;
pd_blocks = bdev_io->u.bdev.num_blocks;
raid_io->base_bdev_io_remaining = 1;
raid1_init_ext_io_opts(bdev_io, &io_opts);
ret = raid_bdev_readv_blocks_ext(base_info, base_ch,
bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt,
pd_lba, pd_blocks, raid1_bdev_io_completion,
raid_io, &io_opts);
if (spdk_likely(ret == 0)) {
raid_io->base_bdev_io_submitted++;
} else if (spdk_unlikely(ret == -ENOMEM)) {
raid_bdev_queue_io_wait(raid_io, base_info->bdev, base_ch,
_raid1_submit_rw_request);
return 0;
}
return ret;
}
static int
raid1_submit_write_request(struct raid_bdev_io *raid_io)
{
struct raid_bdev *raid_bdev = raid_io->raid_bdev;
struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(raid_io);
struct spdk_bdev_ext_io_opts io_opts;
struct raid_base_bdev_info *base_info;
struct spdk_io_channel *base_ch;
uint64_t pd_lba, pd_blocks;
uint16_t idx = raid_io->base_bdev_io_submitted;
uint64_t base_bdev_io_not_submitted;
int ret = 0;
pd_lba = bdev_io->u.bdev.offset_blocks;
pd_blocks = bdev_io->u.bdev.num_blocks;
if (raid_io->base_bdev_io_submitted == 0) {
raid_io->base_bdev_io_remaining = raid_bdev->num_base_bdevs;
}
raid1_init_ext_io_opts(bdev_io, &io_opts);
for (; idx < raid_bdev->num_base_bdevs; idx++) {
base_info = &raid_bdev->base_bdev_info[idx];
base_ch = raid_io->raid_ch->base_channel[idx];
ret = raid_bdev_writev_blocks_ext(base_info, base_ch,
bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt,
pd_lba, pd_blocks, raid1_bdev_io_completion,
raid_io, &io_opts);
if (spdk_unlikely(ret != 0)) {
if (spdk_unlikely(ret == -ENOMEM)) {
raid_bdev_queue_io_wait(raid_io, base_info->bdev, base_ch,
_raid1_submit_rw_request);
return 0;
}
base_bdev_io_not_submitted = raid_bdev->num_base_bdevs -
raid_io->base_bdev_io_submitted;
raid_bdev_io_complete_part(raid_io, base_bdev_io_not_submitted,
SPDK_BDEV_IO_STATUS_FAILED);
return 0;
}
raid_io->base_bdev_io_submitted++;
}
return ret;
}
static void
raid1_submit_rw_request(struct raid_bdev_io *raid_io)
{
struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(raid_io);
int ret;
switch (bdev_io->type) {
case SPDK_BDEV_IO_TYPE_READ:
ret = raid1_submit_read_request(raid_io);
break;
case SPDK_BDEV_IO_TYPE_WRITE:
ret = raid1_submit_write_request(raid_io);
break;
default:
ret = -EINVAL;
break;
}
if (spdk_unlikely(ret != 0)) {
raid_bdev_io_complete(raid_io, SPDK_BDEV_IO_STATUS_FAILED);
}
}
static int
raid1_start(struct raid_bdev *raid_bdev)
{
uint64_t min_blockcnt = UINT64_MAX;
struct raid_base_bdev_info *base_info;
struct raid1_info *r1info;
r1info = calloc(1, sizeof(*r1info));
if (!r1info) {
SPDK_ERRLOG("Failed to allocate RAID1 info device structure\n");
return -ENOMEM;
}
r1info->raid_bdev = raid_bdev;
RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
min_blockcnt = spdk_min(min_blockcnt, base_info->data_size);
}
RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
base_info->data_size = min_blockcnt;
}
raid_bdev->bdev.blockcnt = min_blockcnt;
raid_bdev->module_private = r1info;
return 0;
}
static bool
raid1_stop(struct raid_bdev *raid_bdev)
{
struct raid1_info *r1info = raid_bdev->module_private;
free(r1info);
return true;
}
static struct raid_bdev_module g_raid1_module = {
.level = RAID1,
.base_bdevs_min = 2,
.base_bdevs_constraint = {CONSTRAINT_MIN_BASE_BDEVS_OPERATIONAL, 1},
.memory_domains_supported = true,
.start = raid1_start,
.stop = raid1_stop,
.submit_rw_request = raid1_submit_rw_request,
};
RAID_MODULE_REGISTER(&g_raid1_module)
SPDK_LOG_REGISTER_COMPONENT(bdev_raid1)