Commit 9222ff97 authored by Artur Paszkiewicz's avatar Artur Paszkiewicz Committed by Tomasz Zawadzki
Browse files

module/raid: check for existing superblock on a base_bdev



When adding a new base bdev to a raid bdev (currently only when creating
a new raid bdev) make sure that there is no existing superblock
stored on the base bdev. This prevents accidentally overwriting a base
bdev belonging to a different raid array.

Change-Id: Id5f6c7e3ed7223f6a8fc7455f75831fbbcac7e43
Signed-off-by: default avatarArtur Paszkiewicz <artur.paszkiewicz@intel.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/16164


Community-CI: Mellanox Build Bot
Reviewed-by: default avatarJim Harris <jim.harris@samsung.com>
Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarKonrad Sztyber <konrad.sztyber@intel.com>
parent 8a6bb6a8
Loading
Loading
Loading
Loading
+61 −14
Original line number Diff line number Diff line
@@ -234,8 +234,11 @@ raid_bdev_free_base_bdev_resource(struct raid_base_bdev_info *base_info)
	spdk_put_io_channel(base_info->app_thread_ch);
	base_info->app_thread_ch = NULL;

	if (base_info->is_configured) {
		assert(raid_bdev->num_base_bdevs_discovered);
		raid_bdev->num_base_bdevs_discovered--;
		base_info->is_configured = false;
	}
}

static void
@@ -1614,8 +1617,50 @@ raid_bdev_delete(struct raid_bdev *raid_bdev, raid_bdev_destruct_cb cb_fn, void
	}
}

static void
raid_bdev_configure_base_bdev_cont(struct raid_base_bdev_info *base_info)
{
	struct raid_bdev *raid_bdev = base_info->raid_bdev;
	int rc;

	base_info->is_configured = true;

	raid_bdev->num_base_bdevs_discovered++;
	assert(raid_bdev->num_base_bdevs_discovered <= raid_bdev->num_base_bdevs);

	if (raid_bdev->num_base_bdevs_discovered == raid_bdev->num_base_bdevs) {
		rc = raid_bdev_configure(raid_bdev);
		if (rc != 0) {
			SPDK_ERRLOG("Failed to configure raid bdev: %s\n", spdk_strerror(-rc));
		}
	}
}

static void
raid_bdev_configure_base_bdev_check_sb_cb(const struct raid_bdev_superblock *sb, int status,
		void *ctx)
{
	struct raid_base_bdev_info *base_info = ctx;

	switch (status) {
	case 0:
		/* valid superblock found */
		SPDK_ERRLOG("Existing raid superblock found on bdev %s\n", base_info->name);
		raid_bdev_free_base_bdev_resource(base_info);
		break;
	case -EINVAL:
		/* no valid superblock */
		raid_bdev_configure_base_bdev_cont(base_info);
		break;
	default:
		SPDK_ERRLOG("Failed to examine bdev %s: %s\n",
			    base_info->name, spdk_strerror(-status));
		break;
	}
}

static int
raid_bdev_configure_base_bdev(struct raid_base_bdev_info *base_info)
raid_bdev_configure_base_bdev(struct raid_base_bdev_info *base_info, bool existing)
{
	struct raid_bdev *raid_bdev = base_info->raid_bdev;
	struct spdk_bdev_desc *desc;
@@ -1646,6 +1691,7 @@ raid_bdev_configure_base_bdev(struct raid_base_bdev_info *base_info)
		bdev_name = spdk_bdev_get_name(bdev);

		if (base_info->name == NULL) {
			assert(existing == true);
			base_info->name = strdup(bdev_name);
			if (base_info->name == NULL) {
				return -ENOMEM;
@@ -1739,13 +1785,15 @@ raid_bdev_configure_base_bdev(struct raid_base_bdev_info *base_info)
		goto out;
	}

	raid_bdev->num_base_bdevs_discovered++;
	assert(raid_bdev->num_base_bdevs_discovered <= raid_bdev->num_base_bdevs);

	if (raid_bdev->num_base_bdevs_discovered == raid_bdev->num_base_bdevs) {
		rc = raid_bdev_configure(raid_bdev);
		if (rc != 0) {
			SPDK_ERRLOG("Failed to configure raid bdev: %s\n", spdk_strerror(-rc));
	if (existing) {
		raid_bdev_configure_base_bdev_cont(base_info);
	} else {
		/* check for existing superblock when using a new bdev */
		rc = raid_bdev_load_base_bdev_superblock(desc, base_info->app_thread_ch,
				raid_bdev_configure_base_bdev_check_sb_cb, base_info);
		if (rc) {
			SPDK_ERRLOG("Failed to read bdev %s superblock: %s\n",
				    bdev->name, spdk_strerror(-rc));
		}
	}
out:
@@ -1800,7 +1848,7 @@ raid_bdev_add_base_device(struct raid_bdev *raid_bdev, const char *name, uint8_t
		return -ENOMEM;
	}

	rc = raid_bdev_configure_base_bdev(base_info);
	rc = raid_bdev_configure_base_bdev(base_info, false);
	if (rc != 0) {
		if (rc != -ENODEV) {
			SPDK_ERRLOG("Failed to allocate resource for bdev '%s'\n", name);
@@ -1853,8 +1901,7 @@ raid_bdev_examine_no_sb(struct spdk_bdev *bdev)
		RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
			if (base_info->desc == NULL && base_info->name != NULL &&
			    strcmp(bdev->name, base_info->name) == 0) {
				assert(raid_bdev->sb == NULL);
				raid_bdev_configure_base_bdev(base_info);
				raid_bdev_configure_base_bdev(base_info, true);
				break;
			}
		}
@@ -1954,7 +2001,7 @@ raid_bdev_examine_sb(const struct raid_bdev_superblock *sb, struct spdk_bdev *bd
		return;
	}

	rc = raid_bdev_configure_base_bdev(base_info);
	rc = raid_bdev_configure_base_bdev(base_info, true);
	if (rc != 0) {
		SPDK_ERRLOG("Failed to configure bdev %s as base bdev of raid %s: %s\n",
			    bdev->name, raid_bdev->bdev.name, spdk_strerror(-rc));
+3 −0
Original line number Diff line number Diff line
@@ -87,6 +87,9 @@ struct raid_base_bdev_info {

	/* io channel for the app thread */
	struct spdk_io_channel	*app_thread_ch;

	/* Set to true when base bdev has completed the configuration process */
	bool			is_configured;
};

/*
+34 −5
Original line number Diff line number Diff line
@@ -185,11 +185,13 @@ function has_redundancy() {
function raid_state_function_test() {
	local raid_level=$1
	local num_base_bdevs=$2
	local superblock=$3
	local raid_bdev
	local base_bdevs=($(for ((i = 1; i <= num_base_bdevs; i++)); do echo BaseBdev$i; done))
	local raid_bdev_name="Existed_Raid"
	local strip_size
	local strip_size_create_arg
	local superblock_create_arg

	if [ $raid_level != "raid1" ]; then
		strip_size=64
@@ -198,6 +200,12 @@ function raid_state_function_test() {
		strip_size=0
	fi

	if [ $superblock = true ]; then
		superblock_create_arg="-s"
	else
		superblock_create_arg=""
	fi

	$rootdir/test/app/bdev_svc/bdev_svc -r $rpc_server -i 0 -L bdev_raid &
	raid_pid=$!
	echo "Process raid pid: $raid_pid"
@@ -205,7 +213,7 @@ function raid_state_function_test() {

	# Step1: create a RAID bdev with no base bdevs
	# Expect state: CONFIGURING
	$rpc_py bdev_raid_create $strip_size_create_arg -r $raid_level -b "${base_bdevs[*]}" -n $raid_bdev_name
	$rpc_py bdev_raid_create $strip_size_create_arg $superblock_create_arg -r $raid_level -b "${base_bdevs[*]}" -n $raid_bdev_name
	if ! verify_raid_bdev_state $raid_bdev_name "configuring" $raid_level $strip_size; then
		return 1
	fi
@@ -213,7 +221,7 @@ function raid_state_function_test() {

	# Step2: create one base bdev and add to the RAID bdev
	# Expect state: CONFIGURING
	$rpc_py bdev_raid_create $strip_size_create_arg -r $raid_level -b "${base_bdevs[*]}" -n $raid_bdev_name
	$rpc_py bdev_raid_create $strip_size_create_arg $superblock_create_arg -r $raid_level -b "${base_bdevs[*]}" -n $raid_bdev_name
	$rpc_py bdev_malloc_create 32 512 -b ${base_bdevs[0]}
	waitforbdev ${base_bdevs[0]}
	if ! verify_raid_bdev_state $raid_bdev_name "configuring" $raid_level $strip_size; then
@@ -221,9 +229,16 @@ function raid_state_function_test() {
	fi
	$rpc_py bdev_raid_delete $raid_bdev_name

	if [ $superblock = true ]; then
		# recreate the bdev to remove superblock
		$rpc_py bdev_malloc_delete ${base_bdevs[0]}
		$rpc_py bdev_malloc_create 32 512 -b ${base_bdevs[0]}
		waitforbdev ${base_bdevs[0]}
	fi

	# Step3: create remaining base bdevs and add to the RAID bdev
	# Expect state: ONLINE
	$rpc_py bdev_raid_create $strip_size_create_arg -r $raid_level -b "${base_bdevs[*]}" -n $raid_bdev_name
	$rpc_py bdev_raid_create $strip_size_create_arg $superblock_create_arg -r $raid_level -b "${base_bdevs[*]}" -n $raid_bdev_name
	for ((i = 1; i < num_base_bdevs; i++)); do
		if ! verify_raid_bdev_state $raid_bdev_name "configuring" $raid_level $strip_size; then
			return 1
@@ -375,6 +390,18 @@ function raid_superblock_test() {
		return 1
	fi

	# Try to create new RAID bdev from malloc bdevs
	# Should not reach online state due to superblock still present on base bdevs
	$rpc_py bdev_raid_create $strip_size_create_arg -r $raid_level -b "${base_bdevs_malloc[*]}" -n $raid_bdev_name
	verify_raid_bdev_state $raid_bdev_name "configuring" $raid_level $strip_size

	# Stop the RAID bdev
	$rpc_py bdev_raid_delete $raid_bdev_name
	raid_bdev=$($rpc_py bdev_raid_get_bdevs all | jq -r '.[]')
	if [ -n "$raid_bdev" ]; then
		return 1
	fi

	# Re-add first base bdev
	$rpc_py bdev_passthru_create -b ${base_bdevs_malloc[0]} -p ${base_bdevs_pt[0]} -u ${base_bdevs_pt_uuid[0]}

@@ -414,14 +441,16 @@ raid0_resize_test

for n in {2..4}; do
	for level in raid0 concat raid1; do
		raid_state_function_test $level $n
		raid_state_function_test $level $n false
		raid_state_function_test $level $n true
		raid_superblock_test $level $n
	done
done

if [ "$CONFIG_RAID5F" == y ]; then
	for n in {3..4}; do
		raid_state_function_test raid5f $n
		raid_state_function_test raid5f $n false
		raid_state_function_test raid5f $n true
		raid_superblock_test raid5f $n
	done
fi