xref: /spdk/module/bdev/raid/bdev_raid.c (revision fa3ab73844ced08f4f9487f5de71d477ca5cf604)
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"
142b867a50SArtur Paszkiewicz #include "spdk/likely.h"
158d52c4c2Sxupeng-mingtu #include "spdk/trace.h"
168d52c4c2Sxupeng-mingtu #include "spdk_internal/trace_defs.h"
1707fe6a43SSeth Howell 
1850d58ff3SArtur Paszkiewicz #define RAID_OFFSET_BLOCKS_INVALID	UINT64_MAX
1950d58ff3SArtur Paszkiewicz #define RAID_BDEV_PROCESS_MAX_QD	16
2050d58ff3SArtur Paszkiewicz 
21f39350beSArtur Paszkiewicz #define RAID_BDEV_PROCESS_WINDOW_SIZE_KB_DEFAULT	1024
2289fd1730Sxupeng9 #define RAID_BDEV_PROCESS_MAX_BANDWIDTH_MB_SEC_DEFAULT	0
23f39350beSArtur Paszkiewicz 
2407fe6a43SSeth Howell static bool g_shutdown_started = false;
2507fe6a43SSeth Howell 
2607fe6a43SSeth Howell /* List of all raid bdevs */
2707fe6a43SSeth Howell struct raid_all_tailq g_raid_bdev_list = TAILQ_HEAD_INITIALIZER(g_raid_bdev_list);
2807fe6a43SSeth Howell 
29706029d5SArtur Paszkiewicz static TAILQ_HEAD(, raid_bdev_module) g_raid_modules = TAILQ_HEAD_INITIALIZER(g_raid_modules);
30706029d5SArtur Paszkiewicz 
316e03e49bSArtur Paszkiewicz /*
326e03e49bSArtur Paszkiewicz  * raid_bdev_io_channel is the context of spdk_io_channel for raid bdev device. It
336e03e49bSArtur Paszkiewicz  * contains the relationship of raid bdev io channel with base bdev io channels.
346e03e49bSArtur Paszkiewicz  */
356e03e49bSArtur Paszkiewicz struct raid_bdev_io_channel {
366e03e49bSArtur Paszkiewicz 	/* Array of IO channels of base bdevs */
376e03e49bSArtur Paszkiewicz 	struct spdk_io_channel	**base_channel;
386e03e49bSArtur Paszkiewicz 
396e03e49bSArtur Paszkiewicz 	/* Private raid module IO channel */
406e03e49bSArtur Paszkiewicz 	struct spdk_io_channel	*module_channel;
4150d58ff3SArtur Paszkiewicz 
4250d58ff3SArtur Paszkiewicz 	/* Background process data */
4350d58ff3SArtur Paszkiewicz 	struct {
4450d58ff3SArtur Paszkiewicz 		uint64_t offset;
4550d58ff3SArtur Paszkiewicz 		struct spdk_io_channel *target_ch;
46aae5e04fSArtur Paszkiewicz 		struct raid_bdev_io_channel *ch_processed;
4750d58ff3SArtur Paszkiewicz 	} process;
4850d58ff3SArtur Paszkiewicz };
4950d58ff3SArtur Paszkiewicz 
5050d58ff3SArtur Paszkiewicz enum raid_bdev_process_state {
5150d58ff3SArtur Paszkiewicz 	RAID_PROCESS_STATE_INIT,
5250d58ff3SArtur Paszkiewicz 	RAID_PROCESS_STATE_RUNNING,
5350d58ff3SArtur Paszkiewicz 	RAID_PROCESS_STATE_STOPPING,
5450d58ff3SArtur Paszkiewicz 	RAID_PROCESS_STATE_STOPPED,
5550d58ff3SArtur Paszkiewicz };
5650d58ff3SArtur Paszkiewicz 
5789fd1730Sxupeng9 struct raid_process_qos {
5889fd1730Sxupeng9 	bool enable_qos;
5989fd1730Sxupeng9 	uint64_t last_tsc;
6089fd1730Sxupeng9 	double bytes_per_tsc;
6189fd1730Sxupeng9 	double bytes_available;
6289fd1730Sxupeng9 	double bytes_max;
6389fd1730Sxupeng9 	struct spdk_poller *process_continue_poller;
6489fd1730Sxupeng9 };
6589fd1730Sxupeng9 
6650d58ff3SArtur Paszkiewicz struct raid_bdev_process {
6750d58ff3SArtur Paszkiewicz 	struct raid_bdev		*raid_bdev;
6850d58ff3SArtur Paszkiewicz 	enum raid_process_type		type;
6950d58ff3SArtur Paszkiewicz 	enum raid_bdev_process_state	state;
7050d58ff3SArtur Paszkiewicz 	struct spdk_thread		*thread;
7150d58ff3SArtur Paszkiewicz 	struct raid_bdev_io_channel	*raid_ch;
7250d58ff3SArtur Paszkiewicz 	TAILQ_HEAD(, raid_bdev_process_request) requests;
7350d58ff3SArtur Paszkiewicz 	uint64_t			max_window_size;
7450d58ff3SArtur Paszkiewicz 	uint64_t			window_size;
7550d58ff3SArtur Paszkiewicz 	uint64_t			window_remaining;
7650d58ff3SArtur Paszkiewicz 	int				window_status;
7750d58ff3SArtur Paszkiewicz 	uint64_t			window_offset;
7850d58ff3SArtur Paszkiewicz 	bool				window_range_locked;
7950d58ff3SArtur Paszkiewicz 	struct raid_base_bdev_info	*target;
8050d58ff3SArtur Paszkiewicz 	int				status;
819d2b7b41SArtur Paszkiewicz 	TAILQ_HEAD(, raid_process_finish_action) finish_actions;
8289fd1730Sxupeng9 	struct raid_process_qos		qos;
839d2b7b41SArtur Paszkiewicz };
849d2b7b41SArtur Paszkiewicz 
859d2b7b41SArtur Paszkiewicz struct raid_process_finish_action {
869d2b7b41SArtur Paszkiewicz 	spdk_msg_fn cb;
879d2b7b41SArtur Paszkiewicz 	void *cb_ctx;
889d2b7b41SArtur Paszkiewicz 	TAILQ_ENTRY(raid_process_finish_action) link;
896e03e49bSArtur Paszkiewicz };
906e03e49bSArtur Paszkiewicz 
91f39350beSArtur Paszkiewicz static struct spdk_raid_bdev_opts g_opts = {
92f39350beSArtur Paszkiewicz 	.process_window_size_kb = RAID_BDEV_PROCESS_WINDOW_SIZE_KB_DEFAULT,
9389fd1730Sxupeng9 	.process_max_bandwidth_mb_sec = RAID_BDEV_PROCESS_MAX_BANDWIDTH_MB_SEC_DEFAULT,
94f39350beSArtur Paszkiewicz };
95f39350beSArtur Paszkiewicz 
96f39350beSArtur Paszkiewicz void
97f39350beSArtur Paszkiewicz raid_bdev_get_opts(struct spdk_raid_bdev_opts *opts)
98f39350beSArtur Paszkiewicz {
99f39350beSArtur Paszkiewicz 	*opts = g_opts;
100f39350beSArtur Paszkiewicz }
101f39350beSArtur Paszkiewicz 
102f39350beSArtur Paszkiewicz int
103f39350beSArtur Paszkiewicz raid_bdev_set_opts(const struct spdk_raid_bdev_opts *opts)
104f39350beSArtur Paszkiewicz {
105f39350beSArtur Paszkiewicz 	if (opts->process_window_size_kb == 0) {
106f39350beSArtur Paszkiewicz 		return -EINVAL;
107f39350beSArtur Paszkiewicz 	}
108f39350beSArtur Paszkiewicz 
109f39350beSArtur Paszkiewicz 	g_opts = *opts;
110f39350beSArtur Paszkiewicz 
111f39350beSArtur Paszkiewicz 	return 0;
112f39350beSArtur Paszkiewicz }
113f39350beSArtur Paszkiewicz 
1148dd1cd21SBen Walker static struct raid_bdev_module *
1158dd1cd21SBen Walker raid_bdev_module_find(enum raid_level level)
116706029d5SArtur Paszkiewicz {
117706029d5SArtur Paszkiewicz 	struct raid_bdev_module *raid_module;
118706029d5SArtur Paszkiewicz 
119706029d5SArtur Paszkiewicz 	TAILQ_FOREACH(raid_module, &g_raid_modules, link) {
120706029d5SArtur Paszkiewicz 		if (raid_module->level == level) {
121706029d5SArtur Paszkiewicz 			return raid_module;
122706029d5SArtur Paszkiewicz 		}
123706029d5SArtur Paszkiewicz 	}
124706029d5SArtur Paszkiewicz 
125706029d5SArtur Paszkiewicz 	return NULL;
126706029d5SArtur Paszkiewicz }
127706029d5SArtur Paszkiewicz 
1288dd1cd21SBen Walker void
1298dd1cd21SBen Walker raid_bdev_module_list_add(struct raid_bdev_module *raid_module)
130706029d5SArtur Paszkiewicz {
131706029d5SArtur Paszkiewicz 	if (raid_bdev_module_find(raid_module->level) != NULL) {
132706029d5SArtur Paszkiewicz 		SPDK_ERRLOG("module for raid level '%s' already registered.\n",
133706029d5SArtur Paszkiewicz 			    raid_bdev_level_to_str(raid_module->level));
134706029d5SArtur Paszkiewicz 		assert(false);
135706029d5SArtur Paszkiewicz 	} else {
136706029d5SArtur Paszkiewicz 		TAILQ_INSERT_TAIL(&g_raid_modules, raid_module, link);
137706029d5SArtur Paszkiewicz 	}
138706029d5SArtur Paszkiewicz }
139706029d5SArtur Paszkiewicz 
1406e03e49bSArtur Paszkiewicz struct spdk_io_channel *
1416e03e49bSArtur Paszkiewicz raid_bdev_channel_get_base_channel(struct raid_bdev_io_channel *raid_ch, uint8_t idx)
1426e03e49bSArtur Paszkiewicz {
1436e03e49bSArtur Paszkiewicz 	return raid_ch->base_channel[idx];
1446e03e49bSArtur Paszkiewicz }
1456e03e49bSArtur Paszkiewicz 
1466e03e49bSArtur Paszkiewicz void *
1476e03e49bSArtur Paszkiewicz raid_bdev_channel_get_module_ctx(struct raid_bdev_io_channel *raid_ch)
1486e03e49bSArtur Paszkiewicz {
1496e03e49bSArtur Paszkiewicz 	assert(raid_ch->module_channel != NULL);
1506e03e49bSArtur Paszkiewicz 
1516e03e49bSArtur Paszkiewicz 	return spdk_io_channel_get_ctx(raid_ch->module_channel);
1526e03e49bSArtur Paszkiewicz }
1536e03e49bSArtur Paszkiewicz 
15435a054dbSArtur Paszkiewicz struct raid_base_bdev_info *
15535a054dbSArtur Paszkiewicz raid_bdev_channel_get_base_info(struct raid_bdev_io_channel *raid_ch, struct spdk_bdev *base_bdev)
15635a054dbSArtur Paszkiewicz {
15735a054dbSArtur Paszkiewicz 	struct spdk_io_channel *ch = spdk_io_channel_from_ctx(raid_ch);
15835a054dbSArtur Paszkiewicz 	struct raid_bdev *raid_bdev = spdk_io_channel_get_io_device(ch);
15935a054dbSArtur Paszkiewicz 	uint8_t i;
16035a054dbSArtur Paszkiewicz 
16135a054dbSArtur Paszkiewicz 	for (i = 0; i < raid_bdev->num_base_bdevs; i++) {
16235a054dbSArtur Paszkiewicz 		struct raid_base_bdev_info *base_info = &raid_bdev->base_bdev_info[i];
16335a054dbSArtur Paszkiewicz 
16435a054dbSArtur Paszkiewicz 		if (base_info->is_configured &&
16535a054dbSArtur Paszkiewicz 		    spdk_bdev_desc_get_bdev(base_info->desc) == base_bdev) {
16635a054dbSArtur Paszkiewicz 			return base_info;
16735a054dbSArtur Paszkiewicz 		}
16835a054dbSArtur Paszkiewicz 	}
16935a054dbSArtur Paszkiewicz 
17035a054dbSArtur Paszkiewicz 	return NULL;
17135a054dbSArtur Paszkiewicz }
17235a054dbSArtur Paszkiewicz 
17307fe6a43SSeth Howell /* Function declarations */
17407fe6a43SSeth Howell static void	raid_bdev_examine(struct spdk_bdev *bdev);
17507fe6a43SSeth Howell static int	raid_bdev_init(void);
17607fe6a43SSeth Howell static void	raid_bdev_deconfigure(struct raid_bdev *raid_bdev,
17707fe6a43SSeth Howell 				      raid_bdev_destruct_cb cb_fn, void *cb_arg);
17807fe6a43SSeth Howell 
17950d58ff3SArtur Paszkiewicz static void
18050d58ff3SArtur Paszkiewicz raid_bdev_ch_process_cleanup(struct raid_bdev_io_channel *raid_ch)
18150d58ff3SArtur Paszkiewicz {
18250d58ff3SArtur Paszkiewicz 	raid_ch->process.offset = RAID_OFFSET_BLOCKS_INVALID;
18350d58ff3SArtur Paszkiewicz 
18450d58ff3SArtur Paszkiewicz 	if (raid_ch->process.target_ch != NULL) {
18550d58ff3SArtur Paszkiewicz 		spdk_put_io_channel(raid_ch->process.target_ch);
18650d58ff3SArtur Paszkiewicz 		raid_ch->process.target_ch = NULL;
18750d58ff3SArtur Paszkiewicz 	}
188aae5e04fSArtur Paszkiewicz 
189aae5e04fSArtur Paszkiewicz 	if (raid_ch->process.ch_processed != NULL) {
190aae5e04fSArtur Paszkiewicz 		free(raid_ch->process.ch_processed->base_channel);
191aae5e04fSArtur Paszkiewicz 		free(raid_ch->process.ch_processed);
192aae5e04fSArtur Paszkiewicz 		raid_ch->process.ch_processed = NULL;
193aae5e04fSArtur Paszkiewicz 	}
19450d58ff3SArtur Paszkiewicz }
19550d58ff3SArtur Paszkiewicz 
19650d58ff3SArtur Paszkiewicz static int
19750d58ff3SArtur Paszkiewicz raid_bdev_ch_process_setup(struct raid_bdev_io_channel *raid_ch, struct raid_bdev_process *process)
19850d58ff3SArtur Paszkiewicz {
199aae5e04fSArtur Paszkiewicz 	struct raid_bdev *raid_bdev = process->raid_bdev;
200aae5e04fSArtur Paszkiewicz 	struct raid_bdev_io_channel *raid_ch_processed;
201aae5e04fSArtur Paszkiewicz 	struct raid_base_bdev_info *base_info;
202aae5e04fSArtur Paszkiewicz 
20350d58ff3SArtur Paszkiewicz 	raid_ch->process.offset = process->window_offset;
20450d58ff3SArtur Paszkiewicz 
20550d58ff3SArtur Paszkiewicz 	/* In the future we may have other types of processes which don't use a target bdev,
20650d58ff3SArtur Paszkiewicz 	 * like data scrubbing or strip size migration. Until then, expect that there always is
20750d58ff3SArtur Paszkiewicz 	 * a process target. */
20850d58ff3SArtur Paszkiewicz 	assert(process->target != NULL);
20950d58ff3SArtur Paszkiewicz 
21050d58ff3SArtur Paszkiewicz 	raid_ch->process.target_ch = spdk_bdev_get_io_channel(process->target->desc);
21150d58ff3SArtur Paszkiewicz 	if (raid_ch->process.target_ch == NULL) {
212aae5e04fSArtur Paszkiewicz 		goto err;
21350d58ff3SArtur Paszkiewicz 	}
21450d58ff3SArtur Paszkiewicz 
215aae5e04fSArtur Paszkiewicz 	raid_ch_processed = calloc(1, sizeof(*raid_ch_processed));
216aae5e04fSArtur Paszkiewicz 	if (raid_ch_processed == NULL) {
217aae5e04fSArtur Paszkiewicz 		goto err;
218aae5e04fSArtur Paszkiewicz 	}
219aae5e04fSArtur Paszkiewicz 	raid_ch->process.ch_processed = raid_ch_processed;
220aae5e04fSArtur Paszkiewicz 
221aae5e04fSArtur Paszkiewicz 	raid_ch_processed->base_channel = calloc(raid_bdev->num_base_bdevs,
222aae5e04fSArtur Paszkiewicz 					  sizeof(*raid_ch_processed->base_channel));
223aae5e04fSArtur Paszkiewicz 	if (raid_ch_processed->base_channel == NULL) {
224aae5e04fSArtur Paszkiewicz 		goto err;
225aae5e04fSArtur Paszkiewicz 	}
226aae5e04fSArtur Paszkiewicz 
227aae5e04fSArtur Paszkiewicz 	RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
228aae5e04fSArtur Paszkiewicz 		uint8_t slot = raid_bdev_base_bdev_slot(base_info);
229aae5e04fSArtur Paszkiewicz 
230aae5e04fSArtur Paszkiewicz 		if (base_info != process->target) {
231aae5e04fSArtur Paszkiewicz 			raid_ch_processed->base_channel[slot] = raid_ch->base_channel[slot];
232aae5e04fSArtur Paszkiewicz 		} else {
233aae5e04fSArtur Paszkiewicz 			raid_ch_processed->base_channel[slot] = raid_ch->process.target_ch;
234aae5e04fSArtur Paszkiewicz 		}
235aae5e04fSArtur Paszkiewicz 	}
236aae5e04fSArtur Paszkiewicz 
237aae5e04fSArtur Paszkiewicz 	raid_ch_processed->module_channel = raid_ch->module_channel;
238aae5e04fSArtur Paszkiewicz 	raid_ch_processed->process.offset = RAID_OFFSET_BLOCKS_INVALID;
239aae5e04fSArtur Paszkiewicz 
24050d58ff3SArtur Paszkiewicz 	return 0;
241aae5e04fSArtur Paszkiewicz err:
242aae5e04fSArtur Paszkiewicz 	raid_bdev_ch_process_cleanup(raid_ch);
243aae5e04fSArtur Paszkiewicz 	return -ENOMEM;
24450d58ff3SArtur Paszkiewicz }
24550d58ff3SArtur Paszkiewicz 
24607fe6a43SSeth Howell /*
24707fe6a43SSeth Howell  * brief:
24807fe6a43SSeth Howell  * raid_bdev_create_cb function is a cb function for raid bdev which creates the
24907fe6a43SSeth Howell  * hierarchy from raid bdev to base bdev io channels. It will be called per core
25007fe6a43SSeth Howell  * params:
25107fe6a43SSeth Howell  * io_device - pointer to raid bdev io device represented by raid_bdev
25207fe6a43SSeth Howell  * ctx_buf - pointer to context buffer for raid bdev io channel
25307fe6a43SSeth Howell  * returns:
25407fe6a43SSeth Howell  * 0 - success
25507fe6a43SSeth Howell  * non zero - failure
25607fe6a43SSeth Howell  */
25707fe6a43SSeth Howell static int
25807fe6a43SSeth Howell raid_bdev_create_cb(void *io_device, void *ctx_buf)
25907fe6a43SSeth Howell {
26007fe6a43SSeth Howell 	struct raid_bdev            *raid_bdev = io_device;
26107fe6a43SSeth Howell 	struct raid_bdev_io_channel *raid_ch = ctx_buf;
2629d94e1f5SArtur Paszkiewicz 	uint8_t i;
26350d58ff3SArtur Paszkiewicz 	int ret = -ENOMEM;
26407fe6a43SSeth Howell 
2652172c432STomasz Zawadzki 	SPDK_DEBUGLOG(bdev_raid, "raid_bdev_create_cb, %p\n", raid_ch);
26607fe6a43SSeth Howell 
26707fe6a43SSeth Howell 	assert(raid_bdev != NULL);
26807fe6a43SSeth Howell 	assert(raid_bdev->state == RAID_BDEV_STATE_ONLINE);
26907fe6a43SSeth Howell 
270030dab89SArtur Paszkiewicz 	raid_ch->base_channel = calloc(raid_bdev->num_base_bdevs, sizeof(struct spdk_io_channel *));
27107fe6a43SSeth Howell 	if (!raid_ch->base_channel) {
27207fe6a43SSeth Howell 		SPDK_ERRLOG("Unable to allocate base bdevs io channel\n");
27307fe6a43SSeth Howell 		return -ENOMEM;
27407fe6a43SSeth Howell 	}
275b42cb0e5SArtur Paszkiewicz 
276030dab89SArtur Paszkiewicz 	for (i = 0; i < raid_bdev->num_base_bdevs; i++) {
27707fe6a43SSeth Howell 		/*
27807fe6a43SSeth Howell 		 * Get the spdk_io_channel for all the base bdevs. This is used during
27907fe6a43SSeth Howell 		 * split logic to send the respective child bdev ios to respective base
28007fe6a43SSeth Howell 		 * bdev io channel.
28150d58ff3SArtur Paszkiewicz 		 * Skip missing base bdevs and the process target, which should also be treated as
28250d58ff3SArtur Paszkiewicz 		 * missing until the process completes.
28307fe6a43SSeth Howell 		 */
2846518a98dSArtur Paszkiewicz 		if (raid_bdev->base_bdev_info[i].is_configured == false ||
285a6708553SArtur Paszkiewicz 		    raid_bdev->base_bdev_info[i].is_process_target == true) {
286b42cb0e5SArtur Paszkiewicz 			continue;
287b42cb0e5SArtur Paszkiewicz 		}
28807fe6a43SSeth Howell 		raid_ch->base_channel[i] = spdk_bdev_get_io_channel(
28907fe6a43SSeth Howell 						   raid_bdev->base_bdev_info[i].desc);
29007fe6a43SSeth Howell 		if (!raid_ch->base_channel[i]) {
291c89e2008SArtur Paszkiewicz 			SPDK_ERRLOG("Unable to create io channel for base bdev\n");
29250d58ff3SArtur Paszkiewicz 			goto err;
293c89e2008SArtur Paszkiewicz 		}
294c89e2008SArtur Paszkiewicz 	}
29550d58ff3SArtur Paszkiewicz 
29651978c16SArtur Paszkiewicz 	if (raid_bdev->module->get_io_channel) {
29751978c16SArtur Paszkiewicz 		raid_ch->module_channel = raid_bdev->module->get_io_channel(raid_bdev);
29851978c16SArtur Paszkiewicz 		if (!raid_ch->module_channel) {
29951978c16SArtur Paszkiewicz 			SPDK_ERRLOG("Unable to create io channel for raid module\n");
30051978c16SArtur Paszkiewicz 			goto err;
30151978c16SArtur Paszkiewicz 		}
30251978c16SArtur Paszkiewicz 	}
30351978c16SArtur Paszkiewicz 
30450d58ff3SArtur Paszkiewicz 	if (raid_bdev->process != NULL) {
30550d58ff3SArtur Paszkiewicz 		ret = raid_bdev_ch_process_setup(raid_ch, raid_bdev->process);
30650d58ff3SArtur Paszkiewicz 		if (ret != 0) {
30750d58ff3SArtur Paszkiewicz 			SPDK_ERRLOG("Failed to setup process io channel\n");
30850d58ff3SArtur Paszkiewicz 			goto err;
30950d58ff3SArtur Paszkiewicz 		}
31050d58ff3SArtur Paszkiewicz 	} else {
31150d58ff3SArtur Paszkiewicz 		raid_ch->process.offset = RAID_OFFSET_BLOCKS_INVALID;
31250d58ff3SArtur Paszkiewicz 	}
313c89e2008SArtur Paszkiewicz 
31450d58ff3SArtur Paszkiewicz 	return 0;
31550d58ff3SArtur Paszkiewicz err:
316030dab89SArtur Paszkiewicz 	for (i = 0; i < raid_bdev->num_base_bdevs; i++) {
317b42cb0e5SArtur Paszkiewicz 		if (raid_ch->base_channel[i] != NULL) {
318b42cb0e5SArtur Paszkiewicz 			spdk_put_io_channel(raid_ch->base_channel[i]);
319b42cb0e5SArtur Paszkiewicz 		}
32007fe6a43SSeth Howell 	}
32107fe6a43SSeth Howell 	free(raid_ch->base_channel);
32250d58ff3SArtur Paszkiewicz 
32350d58ff3SArtur Paszkiewicz 	raid_bdev_ch_process_cleanup(raid_ch);
32450d58ff3SArtur Paszkiewicz 
325c89e2008SArtur Paszkiewicz 	return ret;
32607fe6a43SSeth Howell }
32707fe6a43SSeth Howell 
32807fe6a43SSeth Howell /*
32907fe6a43SSeth Howell  * brief:
33007fe6a43SSeth Howell  * raid_bdev_destroy_cb function is a cb function for raid bdev which deletes the
33107fe6a43SSeth Howell  * hierarchy from raid bdev to base bdev io channels. It will be called per core
33207fe6a43SSeth Howell  * params:
33307fe6a43SSeth Howell  * io_device - pointer to raid bdev io device represented by raid_bdev
33407fe6a43SSeth Howell  * ctx_buf - pointer to context buffer for raid bdev io channel
33507fe6a43SSeth Howell  * returns:
33607fe6a43SSeth Howell  * none
33707fe6a43SSeth Howell  */
33807fe6a43SSeth Howell static void
33907fe6a43SSeth Howell raid_bdev_destroy_cb(void *io_device, void *ctx_buf)
34007fe6a43SSeth Howell {
341030dab89SArtur Paszkiewicz 	struct raid_bdev *raid_bdev = io_device;
34207fe6a43SSeth Howell 	struct raid_bdev_io_channel *raid_ch = ctx_buf;
3439d94e1f5SArtur Paszkiewicz 	uint8_t i;
34407fe6a43SSeth Howell 
3452172c432STomasz Zawadzki 	SPDK_DEBUGLOG(bdev_raid, "raid_bdev_destroy_cb\n");
34607fe6a43SSeth Howell 
34707fe6a43SSeth Howell 	assert(raid_ch != NULL);
34807fe6a43SSeth Howell 	assert(raid_ch->base_channel);
349c89e2008SArtur Paszkiewicz 
350c89e2008SArtur Paszkiewicz 	if (raid_ch->module_channel) {
351c89e2008SArtur Paszkiewicz 		spdk_put_io_channel(raid_ch->module_channel);
352c89e2008SArtur Paszkiewicz 	}
353c89e2008SArtur Paszkiewicz 
354030dab89SArtur Paszkiewicz 	for (i = 0; i < raid_bdev->num_base_bdevs; i++) {
35507fe6a43SSeth Howell 		/* Free base bdev channels */
356b42cb0e5SArtur Paszkiewicz 		if (raid_ch->base_channel[i] != NULL) {
35707fe6a43SSeth Howell 			spdk_put_io_channel(raid_ch->base_channel[i]);
35807fe6a43SSeth Howell 		}
359b42cb0e5SArtur Paszkiewicz 	}
36007fe6a43SSeth Howell 	free(raid_ch->base_channel);
36107fe6a43SSeth Howell 	raid_ch->base_channel = NULL;
36250d58ff3SArtur Paszkiewicz 
36350d58ff3SArtur Paszkiewicz 	raid_bdev_ch_process_cleanup(raid_ch);
36407fe6a43SSeth Howell }
36507fe6a43SSeth Howell 
36607fe6a43SSeth Howell /*
36707fe6a43SSeth Howell  * brief:
36895a04949SArtur Paszkiewicz  * raid_bdev_cleanup is used to cleanup raid_bdev related data
36907fe6a43SSeth Howell  * structures.
37007fe6a43SSeth Howell  * params:
37107fe6a43SSeth Howell  * raid_bdev - pointer to raid_bdev
37207fe6a43SSeth Howell  * returns:
37307fe6a43SSeth Howell  * none
37407fe6a43SSeth Howell  */
37507fe6a43SSeth Howell static void
37607fe6a43SSeth Howell raid_bdev_cleanup(struct raid_bdev *raid_bdev)
37707fe6a43SSeth Howell {
378dccdd1e5SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info;
379dccdd1e5SArtur Paszkiewicz 
38046ff15a6SArtur Paszkiewicz 	SPDK_DEBUGLOG(bdev_raid, "raid_bdev_cleanup, %p name %s, state %s\n",
38146ff15a6SArtur Paszkiewicz 		      raid_bdev, raid_bdev->bdev.name, raid_bdev_state_to_str(raid_bdev->state));
38212ed89acSArtur Paszkiewicz 	assert(raid_bdev->state != RAID_BDEV_STATE_ONLINE);
3834dd2a0d3SArtur Paszkiewicz 	assert(spdk_get_thread() == spdk_thread_get_app_thread());
384dccdd1e5SArtur Paszkiewicz 
385dccdd1e5SArtur Paszkiewicz 	RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
386dccdd1e5SArtur Paszkiewicz 		assert(base_info->desc == NULL);
387dccdd1e5SArtur Paszkiewicz 		free(base_info->name);
388dccdd1e5SArtur Paszkiewicz 	}
389dccdd1e5SArtur Paszkiewicz 
39007fe6a43SSeth Howell 	TAILQ_REMOVE(&g_raid_bdev_list, raid_bdev, global_link);
39195a04949SArtur Paszkiewicz }
39295a04949SArtur Paszkiewicz 
39395a04949SArtur Paszkiewicz static void
39495a04949SArtur Paszkiewicz raid_bdev_free(struct raid_bdev *raid_bdev)
39595a04949SArtur Paszkiewicz {
396c25b80e2SArtur Paszkiewicz 	raid_bdev_free_superblock(raid_bdev);
397fbdb05f0SArtur Paszkiewicz 	free(raid_bdev->base_bdev_info);
39895a04949SArtur Paszkiewicz 	free(raid_bdev->bdev.name);
39907fe6a43SSeth Howell 	free(raid_bdev);
40007fe6a43SSeth Howell }
40107fe6a43SSeth Howell 
40295a04949SArtur Paszkiewicz static void
40395a04949SArtur Paszkiewicz raid_bdev_cleanup_and_free(struct raid_bdev *raid_bdev)
40495a04949SArtur Paszkiewicz {
40595a04949SArtur Paszkiewicz 	raid_bdev_cleanup(raid_bdev);
40695a04949SArtur Paszkiewicz 	raid_bdev_free(raid_bdev);
40795a04949SArtur Paszkiewicz }
40895a04949SArtur Paszkiewicz 
4096518a98dSArtur Paszkiewicz static void
4106518a98dSArtur Paszkiewicz raid_bdev_deconfigure_base_bdev(struct raid_base_bdev_info *base_info)
4116518a98dSArtur Paszkiewicz {
4126518a98dSArtur Paszkiewicz 	struct raid_bdev *raid_bdev = base_info->raid_bdev;
4136518a98dSArtur Paszkiewicz 
4146518a98dSArtur Paszkiewicz 	assert(base_info->is_configured);
4156518a98dSArtur Paszkiewicz 	assert(raid_bdev->num_base_bdevs_discovered);
4166518a98dSArtur Paszkiewicz 	raid_bdev->num_base_bdevs_discovered--;
4176518a98dSArtur Paszkiewicz 	base_info->is_configured = false;
418a6708553SArtur Paszkiewicz 	base_info->is_process_target = false;
4196518a98dSArtur Paszkiewicz }
4206518a98dSArtur Paszkiewicz 
42107fe6a43SSeth Howell /*
42207fe6a43SSeth Howell  * brief:
42307fe6a43SSeth Howell  * free resource of base bdev for raid bdev
42407fe6a43SSeth Howell  * params:
425a193dcb8SArtur Paszkiewicz  * base_info - raid base bdev info
42607fe6a43SSeth Howell  * returns:
42777b8f7b6SArtur Paszkiewicz  * none
42807fe6a43SSeth Howell  */
42907fe6a43SSeth Howell static void
43026861b70SArtur Paszkiewicz raid_bdev_free_base_bdev_resource(struct raid_base_bdev_info *base_info)
43107fe6a43SSeth Howell {
43226861b70SArtur Paszkiewicz 	struct raid_bdev *raid_bdev = base_info->raid_bdev;
43326861b70SArtur Paszkiewicz 
4344dd2a0d3SArtur Paszkiewicz 	assert(spdk_get_thread() == spdk_thread_get_app_thread());
435fc2398dfSArtur Paszkiewicz 	assert(base_info->configure_cb == NULL);
4364dd2a0d3SArtur Paszkiewicz 
437dccdd1e5SArtur Paszkiewicz 	free(base_info->name);
438dccdd1e5SArtur Paszkiewicz 	base_info->name = NULL;
4398a6bb6a8SArtur Paszkiewicz 	if (raid_bdev->state != RAID_BDEV_STATE_CONFIGURING) {
4408a6bb6a8SArtur Paszkiewicz 		spdk_uuid_set_null(&base_info->uuid);
4418a6bb6a8SArtur Paszkiewicz 	}
442f1a03e33SArtur Paszkiewicz 	base_info->is_failed = false;
443dccdd1e5SArtur Paszkiewicz 
4443cd7b237SSebastian Brzezinka 	/* clear `data_offset` to allow it to be recalculated during configuration */
4453cd7b237SSebastian Brzezinka 	base_info->data_offset = 0;
4463cd7b237SSebastian Brzezinka 
4478d1993a5SArtur Paszkiewicz 	if (base_info->desc == NULL) {
448dccdd1e5SArtur Paszkiewicz 		return;
449dccdd1e5SArtur Paszkiewicz 	}
450dccdd1e5SArtur Paszkiewicz 
4518d1993a5SArtur Paszkiewicz 	spdk_bdev_module_release_bdev(spdk_bdev_desc_get_bdev(base_info->desc));
452a193dcb8SArtur Paszkiewicz 	spdk_bdev_close(base_info->desc);
453a193dcb8SArtur Paszkiewicz 	base_info->desc = NULL;
45477b8f7b6SArtur Paszkiewicz 	spdk_put_io_channel(base_info->app_thread_ch);
45577b8f7b6SArtur Paszkiewicz 	base_info->app_thread_ch = NULL;
45607fe6a43SSeth Howell 
4579222ff97SArtur Paszkiewicz 	if (base_info->is_configured) {
4586518a98dSArtur Paszkiewicz 		raid_bdev_deconfigure_base_bdev(base_info);
4599222ff97SArtur Paszkiewicz 	}
46007fe6a43SSeth Howell }
46107fe6a43SSeth Howell 
46295a04949SArtur Paszkiewicz static void
46395a04949SArtur Paszkiewicz raid_bdev_io_device_unregister_cb(void *io_device)
46495a04949SArtur Paszkiewicz {
46595a04949SArtur Paszkiewicz 	struct raid_bdev *raid_bdev = io_device;
46695a04949SArtur Paszkiewicz 
46795a04949SArtur Paszkiewicz 	if (raid_bdev->num_base_bdevs_discovered == 0) {
46895a04949SArtur Paszkiewicz 		/* Free raid_bdev when there are no base bdevs left */
46995a04949SArtur Paszkiewicz 		SPDK_DEBUGLOG(bdev_raid, "raid bdev base bdevs is 0, going to free all in destruct\n");
47095a04949SArtur Paszkiewicz 		raid_bdev_cleanup(raid_bdev);
47195a04949SArtur Paszkiewicz 		spdk_bdev_destruct_done(&raid_bdev->bdev, 0);
47295a04949SArtur Paszkiewicz 		raid_bdev_free(raid_bdev);
47395a04949SArtur Paszkiewicz 	} else {
47495a04949SArtur Paszkiewicz 		spdk_bdev_destruct_done(&raid_bdev->bdev, 0);
47595a04949SArtur Paszkiewicz 	}
47695a04949SArtur Paszkiewicz }
47795a04949SArtur Paszkiewicz 
4789cf1ab5bSArtur Paszkiewicz void
4799cf1ab5bSArtur Paszkiewicz raid_bdev_module_stop_done(struct raid_bdev *raid_bdev)
4809cf1ab5bSArtur Paszkiewicz {
4819cf1ab5bSArtur Paszkiewicz 	if (raid_bdev->state != RAID_BDEV_STATE_CONFIGURING) {
4829cf1ab5bSArtur Paszkiewicz 		spdk_io_device_unregister(raid_bdev, raid_bdev_io_device_unregister_cb);
4839cf1ab5bSArtur Paszkiewicz 	}
4849cf1ab5bSArtur Paszkiewicz }
4859cf1ab5bSArtur Paszkiewicz 
4864dd2a0d3SArtur Paszkiewicz static void
4874dd2a0d3SArtur Paszkiewicz _raid_bdev_destruct(void *ctxt)
48807fe6a43SSeth Howell {
48907fe6a43SSeth Howell 	struct raid_bdev *raid_bdev = ctxt;
490a193dcb8SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info;
49107fe6a43SSeth Howell 
4922172c432STomasz Zawadzki 	SPDK_DEBUGLOG(bdev_raid, "raid_bdev_destruct\n");
49307fe6a43SSeth Howell 
4949d2b7b41SArtur Paszkiewicz 	assert(raid_bdev->process == NULL);
4959d2b7b41SArtur Paszkiewicz 
496a193dcb8SArtur Paszkiewicz 	RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
49707fe6a43SSeth Howell 		/*
49807fe6a43SSeth Howell 		 * Close all base bdev descriptors for which call has come from below
49907fe6a43SSeth Howell 		 * layers.  Also close the descriptors if we have started shutdown.
50007fe6a43SSeth Howell 		 */
501dccdd1e5SArtur Paszkiewicz 		if (g_shutdown_started || base_info->remove_scheduled == true) {
50226861b70SArtur Paszkiewicz 			raid_bdev_free_base_bdev_resource(base_info);
50307fe6a43SSeth Howell 		}
50407fe6a43SSeth Howell 	}
50507fe6a43SSeth Howell 
50607fe6a43SSeth Howell 	if (g_shutdown_started) {
50707fe6a43SSeth Howell 		raid_bdev->state = RAID_BDEV_STATE_OFFLINE;
50807fe6a43SSeth Howell 	}
50907fe6a43SSeth Howell 
510df80e8ffSyupeng 	if (raid_bdev->module->stop != NULL) {
5119cf1ab5bSArtur Paszkiewicz 		if (raid_bdev->module->stop(raid_bdev) == false) {
5124dd2a0d3SArtur Paszkiewicz 			return;
5139cf1ab5bSArtur Paszkiewicz 		}
514df80e8ffSyupeng 	}
515df80e8ffSyupeng 
5169cf1ab5bSArtur Paszkiewicz 	raid_bdev_module_stop_done(raid_bdev);
5174dd2a0d3SArtur Paszkiewicz }
5184dd2a0d3SArtur Paszkiewicz 
5194dd2a0d3SArtur Paszkiewicz static int
5204dd2a0d3SArtur Paszkiewicz raid_bdev_destruct(void *ctx)
5214dd2a0d3SArtur Paszkiewicz {
5224dd2a0d3SArtur Paszkiewicz 	spdk_thread_exec_msg(spdk_thread_get_app_thread(), _raid_bdev_destruct, ctx);
52307fe6a43SSeth Howell 
52495a04949SArtur Paszkiewicz 	return 1;
52507fe6a43SSeth Howell }
52607fe6a43SSeth Howell 
5271b9c5629SArtur Paszkiewicz int
528192db8deSSlawomir Ptak raid_bdev_remap_dix_reftag(void *md_buf, uint64_t num_blocks,
529192db8deSSlawomir Ptak 			   struct spdk_bdev *bdev, uint32_t remapped_offset)
530192db8deSSlawomir Ptak {
531192db8deSSlawomir Ptak 	struct spdk_dif_ctx dif_ctx;
532192db8deSSlawomir Ptak 	struct spdk_dif_error err_blk = {};
533192db8deSSlawomir Ptak 	int rc;
534192db8deSSlawomir Ptak 	struct spdk_dif_ctx_init_ext_opts dif_opts;
535192db8deSSlawomir Ptak 	struct iovec md_iov = {
536192db8deSSlawomir Ptak 		.iov_base	= md_buf,
537192db8deSSlawomir Ptak 		.iov_len	= num_blocks * bdev->md_len,
538192db8deSSlawomir Ptak 	};
539192db8deSSlawomir Ptak 
540192db8deSSlawomir Ptak 	if (md_buf == NULL) {
541192db8deSSlawomir Ptak 		return 0;
542192db8deSSlawomir Ptak 	}
543192db8deSSlawomir Ptak 
544192db8deSSlawomir Ptak 	dif_opts.size = SPDK_SIZEOF(&dif_opts, dif_pi_format);
545fcf59a6fSShuhei Matsumoto 	dif_opts.dif_pi_format = bdev->dif_pi_format;
546192db8deSSlawomir Ptak 	rc = spdk_dif_ctx_init(&dif_ctx,
547192db8deSSlawomir Ptak 			       bdev->blocklen, bdev->md_len, bdev->md_interleave,
548192db8deSSlawomir Ptak 			       bdev->dif_is_head_of_md, bdev->dif_type,
549192db8deSSlawomir Ptak 			       SPDK_DIF_FLAGS_REFTAG_CHECK,
550192db8deSSlawomir Ptak 			       0, 0, 0, 0, 0, &dif_opts);
551192db8deSSlawomir Ptak 	if (rc != 0) {
552192db8deSSlawomir Ptak 		SPDK_ERRLOG("Initialization of DIF context failed\n");
553192db8deSSlawomir Ptak 		return rc;
554192db8deSSlawomir Ptak 	}
555192db8deSSlawomir Ptak 
556192db8deSSlawomir Ptak 	spdk_dif_ctx_set_remapped_init_ref_tag(&dif_ctx, remapped_offset);
557192db8deSSlawomir Ptak 
558192db8deSSlawomir Ptak 	rc = spdk_dix_remap_ref_tag(&md_iov, num_blocks, &dif_ctx, &err_blk, false);
559192db8deSSlawomir Ptak 	if (rc != 0) {
560192db8deSSlawomir Ptak 		SPDK_ERRLOG("Remapping reference tag failed. type=%d, offset=%d"
561192db8deSSlawomir Ptak 			    PRIu32 "\n", err_blk.err_type, err_blk.err_offset);
562192db8deSSlawomir Ptak 	}
563192db8deSSlawomir Ptak 
564192db8deSSlawomir Ptak 	return rc;
565192db8deSSlawomir Ptak }
566192db8deSSlawomir Ptak 
567192db8deSSlawomir Ptak int
568192db8deSSlawomir Ptak raid_bdev_verify_dix_reftag(struct iovec *iovs, int iovcnt, void *md_buf,
569192db8deSSlawomir Ptak 			    uint64_t num_blocks, struct spdk_bdev *bdev, uint32_t offset_blocks)
570192db8deSSlawomir Ptak {
571192db8deSSlawomir Ptak 	struct spdk_dif_ctx dif_ctx;
572192db8deSSlawomir Ptak 	struct spdk_dif_error err_blk = {};
573192db8deSSlawomir Ptak 	int rc;
574192db8deSSlawomir Ptak 	struct spdk_dif_ctx_init_ext_opts dif_opts;
575192db8deSSlawomir Ptak 	struct iovec md_iov = {
576192db8deSSlawomir Ptak 		.iov_base	= md_buf,
577192db8deSSlawomir Ptak 		.iov_len	= num_blocks * bdev->md_len,
578192db8deSSlawomir Ptak 	};
579192db8deSSlawomir Ptak 
580192db8deSSlawomir Ptak 	if (md_buf == NULL) {
581192db8deSSlawomir Ptak 		return 0;
582192db8deSSlawomir Ptak 	}
583192db8deSSlawomir Ptak 
584192db8deSSlawomir Ptak 	dif_opts.size = SPDK_SIZEOF(&dif_opts, dif_pi_format);
585fcf59a6fSShuhei Matsumoto 	dif_opts.dif_pi_format = bdev->dif_pi_format;
586192db8deSSlawomir Ptak 	rc = spdk_dif_ctx_init(&dif_ctx,
587192db8deSSlawomir Ptak 			       bdev->blocklen, bdev->md_len, bdev->md_interleave,
588192db8deSSlawomir Ptak 			       bdev->dif_is_head_of_md, bdev->dif_type,
589192db8deSSlawomir Ptak 			       SPDK_DIF_FLAGS_REFTAG_CHECK,
590192db8deSSlawomir Ptak 			       offset_blocks, 0, 0, 0, 0, &dif_opts);
591192db8deSSlawomir Ptak 	if (rc != 0) {
592192db8deSSlawomir Ptak 		SPDK_ERRLOG("Initialization of DIF context failed\n");
593192db8deSSlawomir Ptak 		return rc;
594192db8deSSlawomir Ptak 	}
595192db8deSSlawomir Ptak 
596192db8deSSlawomir Ptak 	rc = spdk_dix_verify(iovs, iovcnt, &md_iov, num_blocks, &dif_ctx, &err_blk);
597192db8deSSlawomir Ptak 	if (rc != 0) {
598192db8deSSlawomir Ptak 		SPDK_ERRLOG("Reference tag check failed. type=%d, offset=%d"
599192db8deSSlawomir Ptak 			    PRIu32 "\n", err_blk.err_type, err_blk.err_offset);
600192db8deSSlawomir Ptak 	}
601192db8deSSlawomir Ptak 
602192db8deSSlawomir Ptak 	return rc;
603192db8deSSlawomir Ptak }
604192db8deSSlawomir Ptak 
6056ba11b19SArtur Paszkiewicz void
6066ba11b19SArtur Paszkiewicz raid_bdev_io_complete(struct raid_bdev_io *raid_io, enum spdk_bdev_io_status status)
6076ba11b19SArtur Paszkiewicz {
6086ba11b19SArtur Paszkiewicz 	struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(raid_io);
609192db8deSSlawomir Ptak 	int rc;
6106ba11b19SArtur Paszkiewicz 
6118d52c4c2Sxupeng-mingtu 	spdk_trace_record(TRACE_BDEV_RAID_IO_DONE, 0, 0, (uintptr_t)raid_io, (uintptr_t)bdev_io);
6128d52c4c2Sxupeng-mingtu 
613aae5e04fSArtur Paszkiewicz 	if (raid_io->split.offset != RAID_OFFSET_BLOCKS_INVALID) {
614aae5e04fSArtur Paszkiewicz 		struct iovec *split_iov = raid_io->split.iov;
615aae5e04fSArtur Paszkiewicz 		const struct iovec *split_iov_orig = &raid_io->split.iov_copy;
616aae5e04fSArtur Paszkiewicz 
617aae5e04fSArtur Paszkiewicz 		/*
618aae5e04fSArtur Paszkiewicz 		 * Non-zero offset here means that this is the completion of the first part of the
619aae5e04fSArtur Paszkiewicz 		 * split I/O (the higher LBAs). Then, we submit the second part and set offset to 0.
620aae5e04fSArtur Paszkiewicz 		 */
621aae5e04fSArtur Paszkiewicz 		if (raid_io->split.offset != 0) {
622aae5e04fSArtur Paszkiewicz 			raid_io->offset_blocks = bdev_io->u.bdev.offset_blocks;
623aae5e04fSArtur Paszkiewicz 			raid_io->md_buf = bdev_io->u.bdev.md_buf;
624aae5e04fSArtur Paszkiewicz 
625aae5e04fSArtur Paszkiewicz 			if (status == SPDK_BDEV_IO_STATUS_SUCCESS) {
626aae5e04fSArtur Paszkiewicz 				raid_io->num_blocks = raid_io->split.offset;
627aae5e04fSArtur Paszkiewicz 				raid_io->iovcnt = raid_io->iovs - bdev_io->u.bdev.iovs;
628aae5e04fSArtur Paszkiewicz 				raid_io->iovs = bdev_io->u.bdev.iovs;
629aae5e04fSArtur Paszkiewicz 				if (split_iov != NULL) {
630aae5e04fSArtur Paszkiewicz 					raid_io->iovcnt++;
631aae5e04fSArtur Paszkiewicz 					split_iov->iov_len = split_iov->iov_base - split_iov_orig->iov_base;
632aae5e04fSArtur Paszkiewicz 					split_iov->iov_base = split_iov_orig->iov_base;
633aae5e04fSArtur Paszkiewicz 				}
634aae5e04fSArtur Paszkiewicz 
635aae5e04fSArtur Paszkiewicz 				raid_io->split.offset = 0;
636aae5e04fSArtur Paszkiewicz 				raid_io->base_bdev_io_submitted = 0;
637aae5e04fSArtur Paszkiewicz 				raid_io->raid_ch = raid_io->raid_ch->process.ch_processed;
638aae5e04fSArtur Paszkiewicz 
639aae5e04fSArtur Paszkiewicz 				raid_io->raid_bdev->module->submit_rw_request(raid_io);
640aae5e04fSArtur Paszkiewicz 				return;
641aae5e04fSArtur Paszkiewicz 			}
642aae5e04fSArtur Paszkiewicz 		}
643aae5e04fSArtur Paszkiewicz 
644aae5e04fSArtur Paszkiewicz 		raid_io->num_blocks = bdev_io->u.bdev.num_blocks;
645aae5e04fSArtur Paszkiewicz 		raid_io->iovcnt = bdev_io->u.bdev.iovcnt;
646aae5e04fSArtur Paszkiewicz 		raid_io->iovs = bdev_io->u.bdev.iovs;
647aae5e04fSArtur Paszkiewicz 		if (split_iov != NULL) {
648aae5e04fSArtur Paszkiewicz 			*split_iov = *split_iov_orig;
649aae5e04fSArtur Paszkiewicz 		}
650aae5e04fSArtur Paszkiewicz 	}
651aae5e04fSArtur Paszkiewicz 
6522b867a50SArtur Paszkiewicz 	if (spdk_unlikely(raid_io->completion_cb != NULL)) {
6532b867a50SArtur Paszkiewicz 		raid_io->completion_cb(raid_io, status);
6542b867a50SArtur Paszkiewicz 	} else {
655192db8deSSlawomir Ptak 		if (spdk_unlikely(bdev_io->type == SPDK_BDEV_IO_TYPE_READ &&
656192db8deSSlawomir Ptak 				  spdk_bdev_get_dif_type(bdev_io->bdev) != SPDK_DIF_DISABLE &&
657192db8deSSlawomir Ptak 				  bdev_io->bdev->dif_check_flags & SPDK_DIF_FLAGS_REFTAG_CHECK &&
658192db8deSSlawomir Ptak 				  status == SPDK_BDEV_IO_STATUS_SUCCESS)) {
659192db8deSSlawomir Ptak 
660192db8deSSlawomir Ptak 			rc = raid_bdev_remap_dix_reftag(bdev_io->u.bdev.md_buf,
661192db8deSSlawomir Ptak 							bdev_io->u.bdev.num_blocks, bdev_io->bdev,
662192db8deSSlawomir Ptak 							bdev_io->u.bdev.offset_blocks);
663192db8deSSlawomir Ptak 			if (rc != 0) {
664192db8deSSlawomir Ptak 				status = SPDK_BDEV_IO_STATUS_FAILED;
665192db8deSSlawomir Ptak 			}
666192db8deSSlawomir Ptak 		}
6676ba11b19SArtur Paszkiewicz 		spdk_bdev_io_complete(bdev_io, status);
6686ba11b19SArtur Paszkiewicz 	}
6692b867a50SArtur Paszkiewicz }
6706ba11b19SArtur Paszkiewicz 
67107fe6a43SSeth Howell /*
67207fe6a43SSeth Howell  * brief:
6732efe6d92SArtur Paszkiewicz  * raid_bdev_io_complete_part - signal the completion of a part of the expected
6742efe6d92SArtur Paszkiewicz  * base bdev IOs and complete the raid_io if this is the final expected IO.
6752efe6d92SArtur Paszkiewicz  * The caller should first set raid_io->base_bdev_io_remaining. This function
6762efe6d92SArtur Paszkiewicz  * will decrement this counter by the value of the 'completed' parameter and
6772efe6d92SArtur Paszkiewicz  * complete the raid_io if the counter reaches 0. The caller is free to
6782efe6d92SArtur Paszkiewicz  * interpret the 'base_bdev_io_remaining' and 'completed' values as needed,
6792efe6d92SArtur Paszkiewicz  * it can represent e.g. blocks or IOs.
680a5d9d778Spaul luse  * params:
6812efe6d92SArtur Paszkiewicz  * raid_io - pointer to raid_bdev_io
6822efe6d92SArtur Paszkiewicz  * completed - the part of the raid_io that has been completed
6832efe6d92SArtur Paszkiewicz  * status - status of the base IO
684a5d9d778Spaul luse  * returns:
6852efe6d92SArtur Paszkiewicz  * true - if the raid_io is completed
6862efe6d92SArtur Paszkiewicz  * false - otherwise
687a5d9d778Spaul luse  */
6882efe6d92SArtur Paszkiewicz bool
6892efe6d92SArtur Paszkiewicz raid_bdev_io_complete_part(struct raid_bdev_io *raid_io, uint64_t completed,
6902efe6d92SArtur Paszkiewicz 			   enum spdk_bdev_io_status status)
691a5d9d778Spaul luse {
6922efe6d92SArtur Paszkiewicz 	assert(raid_io->base_bdev_io_remaining >= completed);
6932efe6d92SArtur Paszkiewicz 	raid_io->base_bdev_io_remaining -= completed;
694a5d9d778Spaul luse 
6959820a949SArtur Paszkiewicz 	if (status != raid_io->base_bdev_io_status_default) {
6962efe6d92SArtur Paszkiewicz 		raid_io->base_bdev_io_status = status;
697a5d9d778Spaul luse 	}
698a5d9d778Spaul luse 
6992efe6d92SArtur Paszkiewicz 	if (raid_io->base_bdev_io_remaining == 0) {
7006ba11b19SArtur Paszkiewicz 		raid_bdev_io_complete(raid_io, raid_io->base_bdev_io_status);
7012efe6d92SArtur Paszkiewicz 		return true;
7022efe6d92SArtur Paszkiewicz 	} else {
7032efe6d92SArtur Paszkiewicz 		return false;
704a5d9d778Spaul luse 	}
705a5d9d778Spaul luse }
706a5d9d778Spaul luse 
70707fe6a43SSeth Howell /*
70807fe6a43SSeth Howell  * brief:
7091d246e97SArtur Paszkiewicz  * raid_bdev_queue_io_wait function processes the IO which failed to submit.
7101d246e97SArtur Paszkiewicz  * It will try to queue the IOs after storing the context to bdev wait queue logic.
71107fe6a43SSeth Howell  * params:
712ae70d6a4SArtur Paszkiewicz  * raid_io - pointer to raid_bdev_io
713ae70d6a4SArtur Paszkiewicz  * bdev - the block device that the IO is submitted to
714ae70d6a4SArtur Paszkiewicz  * ch - io channel
715ae70d6a4SArtur Paszkiewicz  * cb_fn - callback when the spdk_bdev_io for bdev becomes available
71607fe6a43SSeth Howell  * returns:
71707fe6a43SSeth Howell  * none
71807fe6a43SSeth Howell  */
719fc9ca1d0SArtur Paszkiewicz void
720ae70d6a4SArtur Paszkiewicz raid_bdev_queue_io_wait(struct raid_bdev_io *raid_io, struct spdk_bdev *bdev,
721ae70d6a4SArtur Paszkiewicz 			struct spdk_io_channel *ch, spdk_bdev_io_wait_cb cb_fn)
72207fe6a43SSeth Howell {
723ae70d6a4SArtur Paszkiewicz 	raid_io->waitq_entry.bdev = bdev;
72407fe6a43SSeth Howell 	raid_io->waitq_entry.cb_fn = cb_fn;
725ae70d6a4SArtur Paszkiewicz 	raid_io->waitq_entry.cb_arg = raid_io;
726ae70d6a4SArtur Paszkiewicz 	spdk_bdev_queue_io_wait(bdev, ch, &raid_io->waitq_entry);
72707fe6a43SSeth Howell }
72807fe6a43SSeth Howell 
7290ae5a89dSArtur Paszkiewicz static void
7302efe6d92SArtur Paszkiewicz raid_base_bdev_reset_complete(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
7312efe6d92SArtur Paszkiewicz {
7322efe6d92SArtur Paszkiewicz 	struct raid_bdev_io *raid_io = cb_arg;
7332efe6d92SArtur Paszkiewicz 
7342efe6d92SArtur Paszkiewicz 	spdk_bdev_free_io(bdev_io);
7352efe6d92SArtur Paszkiewicz 
7362efe6d92SArtur Paszkiewicz 	raid_bdev_io_complete_part(raid_io, 1, success ?
7372efe6d92SArtur Paszkiewicz 				   SPDK_BDEV_IO_STATUS_SUCCESS :
7382efe6d92SArtur Paszkiewicz 				   SPDK_BDEV_IO_STATUS_FAILED);
7392efe6d92SArtur Paszkiewicz }
7402efe6d92SArtur Paszkiewicz 
7418dd1cd21SBen Walker static void raid_bdev_submit_reset_request(struct raid_bdev_io *raid_io);
7420ae5a89dSArtur Paszkiewicz 
7430ae5a89dSArtur Paszkiewicz static void
744ae70d6a4SArtur Paszkiewicz _raid_bdev_submit_reset_request(void *_raid_io)
7450ae5a89dSArtur Paszkiewicz {
746ae70d6a4SArtur Paszkiewicz 	struct raid_bdev_io *raid_io = _raid_io;
7470ae5a89dSArtur Paszkiewicz 
7480ae5a89dSArtur Paszkiewicz 	raid_bdev_submit_reset_request(raid_io);
7490ae5a89dSArtur Paszkiewicz }
7500ae5a89dSArtur Paszkiewicz 
75107fe6a43SSeth Howell /*
75207fe6a43SSeth Howell  * brief:
7530ae5a89dSArtur Paszkiewicz  * raid_bdev_submit_reset_request function submits reset requests
75407fe6a43SSeth Howell  * to member disks; it will submit as many as possible unless a reset fails with -ENOMEM, in
75507fe6a43SSeth Howell  * which case it will queue it for later submission
75607fe6a43SSeth Howell  * params:
7570ae5a89dSArtur Paszkiewicz  * raid_io
75807fe6a43SSeth Howell  * returns:
75907fe6a43SSeth Howell  * none
76007fe6a43SSeth Howell  */
76107fe6a43SSeth Howell static void
7620ae5a89dSArtur Paszkiewicz raid_bdev_submit_reset_request(struct raid_bdev_io *raid_io)
76307fe6a43SSeth Howell {
76407fe6a43SSeth Howell 	struct raid_bdev		*raid_bdev;
76507fe6a43SSeth Howell 	int				ret;
76607fe6a43SSeth Howell 	uint8_t				i;
767235cc2c9SArtur Paszkiewicz 	struct raid_base_bdev_info	*base_info;
768235cc2c9SArtur Paszkiewicz 	struct spdk_io_channel		*base_ch;
76907fe6a43SSeth Howell 
770cb8dbf17SArtur Paszkiewicz 	raid_bdev = raid_io->raid_bdev;
77107fe6a43SSeth Howell 
7722efe6d92SArtur Paszkiewicz 	if (raid_io->base_bdev_io_remaining == 0) {
7732efe6d92SArtur Paszkiewicz 		raid_io->base_bdev_io_remaining = raid_bdev->num_base_bdevs;
7742efe6d92SArtur Paszkiewicz 	}
77577b8618eSArtur Paszkiewicz 
776fe7932a5SArtur Paszkiewicz 	for (i = raid_io->base_bdev_io_submitted; i < raid_bdev->num_base_bdevs; i++) {
777235cc2c9SArtur Paszkiewicz 		base_info = &raid_bdev->base_bdev_info[i];
778235cc2c9SArtur Paszkiewicz 		base_ch = raid_io->raid_ch->base_channel[i];
779b42cb0e5SArtur Paszkiewicz 		if (base_ch == NULL) {
780b42cb0e5SArtur Paszkiewicz 			raid_io->base_bdev_io_submitted++;
781b42cb0e5SArtur Paszkiewicz 			raid_bdev_io_complete_part(raid_io, 1, SPDK_BDEV_IO_STATUS_SUCCESS);
782b42cb0e5SArtur Paszkiewicz 			continue;
783b42cb0e5SArtur Paszkiewicz 		}
784235cc2c9SArtur Paszkiewicz 		ret = spdk_bdev_reset(base_info->desc, base_ch,
7852efe6d92SArtur Paszkiewicz 				      raid_base_bdev_reset_complete, raid_io);
78607fe6a43SSeth Howell 		if (ret == 0) {
78707fe6a43SSeth Howell 			raid_io->base_bdev_io_submitted++;
788d3a04643SArtur Paszkiewicz 		} else if (ret == -ENOMEM) {
7898d1993a5SArtur Paszkiewicz 			raid_bdev_queue_io_wait(raid_io, spdk_bdev_desc_get_bdev(base_info->desc),
7908d1993a5SArtur Paszkiewicz 						base_ch, _raid_bdev_submit_reset_request);
791d3a04643SArtur Paszkiewicz 			return;
792d3a04643SArtur Paszkiewicz 		} else {
793d3a04643SArtur Paszkiewicz 			SPDK_ERRLOG("bdev io submit error not due to ENOMEM, it should not happen\n");
794d3a04643SArtur Paszkiewicz 			assert(false);
7956ba11b19SArtur Paszkiewicz 			raid_bdev_io_complete(raid_io, SPDK_BDEV_IO_STATUS_FAILED);
79607fe6a43SSeth Howell 			return;
79707fe6a43SSeth Howell 		}
79807fe6a43SSeth Howell 	}
79907fe6a43SSeth Howell }
80007fe6a43SSeth Howell 
801aae5e04fSArtur Paszkiewicz static void
802aae5e04fSArtur Paszkiewicz raid_bdev_io_split(struct raid_bdev_io *raid_io, uint64_t split_offset)
803aae5e04fSArtur Paszkiewicz {
804aae5e04fSArtur Paszkiewicz 	struct raid_bdev *raid_bdev = raid_io->raid_bdev;
805bb374988SArtur Paszkiewicz 	size_t iov_offset = split_offset * raid_bdev->bdev.blocklen;
806aae5e04fSArtur Paszkiewicz 	int i;
807aae5e04fSArtur Paszkiewicz 
808aae5e04fSArtur Paszkiewicz 	assert(split_offset != 0);
809aae5e04fSArtur Paszkiewicz 	assert(raid_io->split.offset == RAID_OFFSET_BLOCKS_INVALID);
810aae5e04fSArtur Paszkiewicz 	raid_io->split.offset = split_offset;
811aae5e04fSArtur Paszkiewicz 
812aae5e04fSArtur Paszkiewicz 	raid_io->offset_blocks += split_offset;
813aae5e04fSArtur Paszkiewicz 	raid_io->num_blocks -= split_offset;
814aae5e04fSArtur Paszkiewicz 	if (raid_io->md_buf != NULL) {
815aae5e04fSArtur Paszkiewicz 		raid_io->md_buf += (split_offset * raid_bdev->bdev.md_len);
816aae5e04fSArtur Paszkiewicz 	}
817aae5e04fSArtur Paszkiewicz 
818aae5e04fSArtur Paszkiewicz 	for (i = 0; i < raid_io->iovcnt; i++) {
819aae5e04fSArtur Paszkiewicz 		struct iovec *iov = &raid_io->iovs[i];
820aae5e04fSArtur Paszkiewicz 
821aae5e04fSArtur Paszkiewicz 		if (iov_offset < iov->iov_len) {
822aae5e04fSArtur Paszkiewicz 			if (iov_offset == 0) {
823aae5e04fSArtur Paszkiewicz 				raid_io->split.iov = NULL;
824aae5e04fSArtur Paszkiewicz 			} else {
825aae5e04fSArtur Paszkiewicz 				raid_io->split.iov = iov;
826aae5e04fSArtur Paszkiewicz 				raid_io->split.iov_copy = *iov;
827aae5e04fSArtur Paszkiewicz 				iov->iov_base += iov_offset;
828aae5e04fSArtur Paszkiewicz 				iov->iov_len -= iov_offset;
829aae5e04fSArtur Paszkiewicz 			}
830aae5e04fSArtur Paszkiewicz 			raid_io->iovs += i;
831aae5e04fSArtur Paszkiewicz 			raid_io->iovcnt -= i;
832aae5e04fSArtur Paszkiewicz 			break;
833aae5e04fSArtur Paszkiewicz 		}
834aae5e04fSArtur Paszkiewicz 
835aae5e04fSArtur Paszkiewicz 		iov_offset -= iov->iov_len;
836aae5e04fSArtur Paszkiewicz 	}
837aae5e04fSArtur Paszkiewicz }
838aae5e04fSArtur Paszkiewicz 
839aae5e04fSArtur Paszkiewicz static void
840aae5e04fSArtur Paszkiewicz raid_bdev_submit_rw_request(struct raid_bdev_io *raid_io)
841aae5e04fSArtur Paszkiewicz {
842aae5e04fSArtur Paszkiewicz 	struct raid_bdev_io_channel *raid_ch = raid_io->raid_ch;
843aae5e04fSArtur Paszkiewicz 
844aae5e04fSArtur Paszkiewicz 	if (raid_ch->process.offset != RAID_OFFSET_BLOCKS_INVALID) {
845aae5e04fSArtur Paszkiewicz 		uint64_t offset_begin = raid_io->offset_blocks;
846aae5e04fSArtur Paszkiewicz 		uint64_t offset_end = offset_begin + raid_io->num_blocks;
847aae5e04fSArtur Paszkiewicz 
848aae5e04fSArtur Paszkiewicz 		if (offset_end > raid_ch->process.offset) {
849aae5e04fSArtur Paszkiewicz 			if (offset_begin < raid_ch->process.offset) {
850aae5e04fSArtur Paszkiewicz 				/*
851aae5e04fSArtur Paszkiewicz 				 * If the I/O spans both the processed and unprocessed ranges,
852aae5e04fSArtur Paszkiewicz 				 * split it and first handle the unprocessed part. After it
853aae5e04fSArtur Paszkiewicz 				 * completes, the rest will be handled.
854aae5e04fSArtur Paszkiewicz 				 * This situation occurs when the process thread is not active
855aae5e04fSArtur Paszkiewicz 				 * or is waiting for the process window range to be locked
856aae5e04fSArtur Paszkiewicz 				 * (quiesced). When a window is being processed, such I/Os will be
857aae5e04fSArtur Paszkiewicz 				 * deferred by the bdev layer until the window is unlocked.
858aae5e04fSArtur Paszkiewicz 				 */
859aae5e04fSArtur Paszkiewicz 				SPDK_DEBUGLOG(bdev_raid, "split: process_offset: %lu offset_begin: %lu offset_end: %lu\n",
860aae5e04fSArtur Paszkiewicz 					      raid_ch->process.offset, offset_begin, offset_end);
861aae5e04fSArtur Paszkiewicz 				raid_bdev_io_split(raid_io, raid_ch->process.offset - offset_begin);
862aae5e04fSArtur Paszkiewicz 			}
863aae5e04fSArtur Paszkiewicz 		} else {
864aae5e04fSArtur Paszkiewicz 			/* Use the child channel, which corresponds to the already processed range */
865aae5e04fSArtur Paszkiewicz 			raid_io->raid_ch = raid_ch->process.ch_processed;
866aae5e04fSArtur Paszkiewicz 		}
867aae5e04fSArtur Paszkiewicz 	}
868aae5e04fSArtur Paszkiewicz 
869aae5e04fSArtur Paszkiewicz 	raid_io->raid_bdev->module->submit_rw_request(raid_io);
870aae5e04fSArtur Paszkiewicz }
871aae5e04fSArtur Paszkiewicz 
87207fe6a43SSeth Howell /*
87307fe6a43SSeth Howell  * brief:
87407fe6a43SSeth Howell  * Callback function to spdk_bdev_io_get_buf.
87507fe6a43SSeth Howell  * params:
87607fe6a43SSeth Howell  * ch - pointer to raid bdev io channel
87707fe6a43SSeth Howell  * bdev_io - pointer to parent bdev_io on raid bdev device
87807fe6a43SSeth Howell  * success - True if buffer is allocated or false otherwise.
87907fe6a43SSeth Howell  * returns:
88007fe6a43SSeth Howell  * none
88107fe6a43SSeth Howell  */
88207fe6a43SSeth Howell static void
88307fe6a43SSeth Howell raid_bdev_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io,
88407fe6a43SSeth Howell 		     bool success)
88507fe6a43SSeth Howell {
8860ae5a89dSArtur Paszkiewicz 	struct raid_bdev_io *raid_io = (struct raid_bdev_io *)bdev_io->driver_ctx;
8870ae5a89dSArtur Paszkiewicz 
88807fe6a43SSeth Howell 	if (!success) {
8896ba11b19SArtur Paszkiewicz 		raid_bdev_io_complete(raid_io, SPDK_BDEV_IO_STATUS_FAILED);
89007fe6a43SSeth Howell 		return;
89107fe6a43SSeth Howell 	}
89207fe6a43SSeth Howell 
8935031f0f3SSlawomir Ptak 	raid_io->iovs = bdev_io->u.bdev.iovs;
8945031f0f3SSlawomir Ptak 	raid_io->iovcnt = bdev_io->u.bdev.iovcnt;
8955031f0f3SSlawomir Ptak 	raid_io->md_buf = bdev_io->u.bdev.md_buf;
8965031f0f3SSlawomir Ptak 
897aae5e04fSArtur Paszkiewicz 	raid_bdev_submit_rw_request(raid_io);
89807fe6a43SSeth Howell }
89907fe6a43SSeth Howell 
900a4e1703eSArtur Paszkiewicz void
901a4e1703eSArtur Paszkiewicz raid_bdev_io_init(struct raid_bdev_io *raid_io, struct raid_bdev_io_channel *raid_ch,
902a4e1703eSArtur Paszkiewicz 		  enum spdk_bdev_io_type type, uint64_t offset_blocks,
903a4e1703eSArtur Paszkiewicz 		  uint64_t num_blocks, struct iovec *iovs, int iovcnt, void *md_buf,
904a4e1703eSArtur Paszkiewicz 		  struct spdk_memory_domain *memory_domain, void *memory_domain_ctx)
905a4e1703eSArtur Paszkiewicz {
906a4e1703eSArtur Paszkiewicz 	struct spdk_io_channel *ch = spdk_io_channel_from_ctx(raid_ch);
907a4e1703eSArtur Paszkiewicz 	struct raid_bdev *raid_bdev = spdk_io_channel_get_io_device(ch);
908a4e1703eSArtur Paszkiewicz 
909a4e1703eSArtur Paszkiewicz 	raid_io->type = type;
910a4e1703eSArtur Paszkiewicz 	raid_io->offset_blocks = offset_blocks;
911a4e1703eSArtur Paszkiewicz 	raid_io->num_blocks = num_blocks;
912a4e1703eSArtur Paszkiewicz 	raid_io->iovs = iovs;
913a4e1703eSArtur Paszkiewicz 	raid_io->iovcnt = iovcnt;
914a4e1703eSArtur Paszkiewicz 	raid_io->memory_domain = memory_domain;
915a4e1703eSArtur Paszkiewicz 	raid_io->memory_domain_ctx = memory_domain_ctx;
916a4e1703eSArtur Paszkiewicz 	raid_io->md_buf = md_buf;
917a4e1703eSArtur Paszkiewicz 
918a4e1703eSArtur Paszkiewicz 	raid_io->raid_bdev = raid_bdev;
919a4e1703eSArtur Paszkiewicz 	raid_io->raid_ch = raid_ch;
920a4e1703eSArtur Paszkiewicz 	raid_io->base_bdev_io_remaining = 0;
921a4e1703eSArtur Paszkiewicz 	raid_io->base_bdev_io_submitted = 0;
9222b867a50SArtur Paszkiewicz 	raid_io->completion_cb = NULL;
923aae5e04fSArtur Paszkiewicz 	raid_io->split.offset = RAID_OFFSET_BLOCKS_INVALID;
9249820a949SArtur Paszkiewicz 
9259820a949SArtur Paszkiewicz 	raid_bdev_io_set_default_status(raid_io, SPDK_BDEV_IO_STATUS_SUCCESS);
926a4e1703eSArtur Paszkiewicz }
927a4e1703eSArtur Paszkiewicz 
92807fe6a43SSeth Howell /*
92907fe6a43SSeth Howell  * brief:
93007fe6a43SSeth Howell  * raid_bdev_submit_request function is the submit_request function pointer of
93107fe6a43SSeth Howell  * raid bdev function table. This is used to submit the io on raid_bdev to below
93207fe6a43SSeth Howell  * layers.
93307fe6a43SSeth Howell  * params:
93407fe6a43SSeth Howell  * ch - pointer to raid bdev io channel
93507fe6a43SSeth Howell  * bdev_io - pointer to parent bdev_io on raid bdev device
93607fe6a43SSeth Howell  * returns:
93707fe6a43SSeth Howell  * none
93807fe6a43SSeth Howell  */
93907fe6a43SSeth Howell static void
94007fe6a43SSeth Howell raid_bdev_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
94107fe6a43SSeth Howell {
942485c7912SArtur Paszkiewicz 	struct raid_bdev_io *raid_io = (struct raid_bdev_io *)bdev_io->driver_ctx;
943485c7912SArtur Paszkiewicz 
944a4e1703eSArtur Paszkiewicz 	raid_bdev_io_init(raid_io, spdk_io_channel_get_ctx(ch), bdev_io->type,
945a4e1703eSArtur Paszkiewicz 			  bdev_io->u.bdev.offset_blocks, bdev_io->u.bdev.num_blocks,
946a4e1703eSArtur Paszkiewicz 			  bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt, bdev_io->u.bdev.md_buf,
947a4e1703eSArtur Paszkiewicz 			  bdev_io->u.bdev.memory_domain, bdev_io->u.bdev.memory_domain_ctx);
948485c7912SArtur Paszkiewicz 
9498d52c4c2Sxupeng-mingtu 	spdk_trace_record(TRACE_BDEV_RAID_IO_START, 0, 0, (uintptr_t)raid_io, (uintptr_t)bdev_io);
9508d52c4c2Sxupeng-mingtu 
95107fe6a43SSeth Howell 	switch (bdev_io->type) {
95207fe6a43SSeth Howell 	case SPDK_BDEV_IO_TYPE_READ:
95307fe6a43SSeth Howell 		spdk_bdev_io_get_buf(bdev_io, raid_bdev_get_buf_cb,
95407fe6a43SSeth Howell 				     bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen);
95507fe6a43SSeth Howell 		break;
95607fe6a43SSeth Howell 	case SPDK_BDEV_IO_TYPE_WRITE:
957aae5e04fSArtur Paszkiewicz 		raid_bdev_submit_rw_request(raid_io);
95807fe6a43SSeth Howell 		break;
95907fe6a43SSeth Howell 
96007fe6a43SSeth Howell 	case SPDK_BDEV_IO_TYPE_RESET:
9610ae5a89dSArtur Paszkiewicz 		raid_bdev_submit_reset_request(raid_io);
96207fe6a43SSeth Howell 		break;
96307fe6a43SSeth Howell 
96407fe6a43SSeth Howell 	case SPDK_BDEV_IO_TYPE_FLUSH:
96507fe6a43SSeth Howell 	case SPDK_BDEV_IO_TYPE_UNMAP:
966aae5e04fSArtur Paszkiewicz 		if (raid_io->raid_bdev->process != NULL) {
967aae5e04fSArtur Paszkiewicz 			/* TODO: rebuild support */
968aae5e04fSArtur Paszkiewicz 			raid_bdev_io_complete(raid_io, SPDK_BDEV_IO_STATUS_FAILED);
969aae5e04fSArtur Paszkiewicz 			return;
970aae5e04fSArtur Paszkiewicz 		}
971182278c0SArtur Paszkiewicz 		raid_io->raid_bdev->module->submit_null_payload_request(raid_io);
97207fe6a43SSeth Howell 		break;
97307fe6a43SSeth Howell 
97407fe6a43SSeth Howell 	default:
97507fe6a43SSeth Howell 		SPDK_ERRLOG("submit request, invalid io type %u\n", bdev_io->type);
9766ba11b19SArtur Paszkiewicz 		raid_bdev_io_complete(raid_io, SPDK_BDEV_IO_STATUS_FAILED);
97707fe6a43SSeth Howell 		break;
97807fe6a43SSeth Howell 	}
97907fe6a43SSeth Howell }
98007fe6a43SSeth Howell 
98107fe6a43SSeth Howell /*
98207fe6a43SSeth Howell  * brief:
98307fe6a43SSeth Howell  * _raid_bdev_io_type_supported checks whether io_type is supported in
98407fe6a43SSeth Howell  * all base bdev modules of raid bdev module. If anyone among the base_bdevs
98507fe6a43SSeth Howell  * doesn't support, the raid device doesn't supports.
98607fe6a43SSeth Howell  *
98707fe6a43SSeth Howell  * params:
98807fe6a43SSeth Howell  * raid_bdev - pointer to raid bdev context
98907fe6a43SSeth Howell  * io_type - io type
99007fe6a43SSeth Howell  * returns:
99107fe6a43SSeth Howell  * true - io_type is supported
99207fe6a43SSeth Howell  * false - io_type is not supported
99307fe6a43SSeth Howell  */
99407fe6a43SSeth Howell inline static bool
99507fe6a43SSeth Howell _raid_bdev_io_type_supported(struct raid_bdev *raid_bdev, enum spdk_bdev_io_type io_type)
99607fe6a43SSeth Howell {
997a193dcb8SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info;
99807fe6a43SSeth Howell 
9991d3ca5c4SArtur Paszkiewicz 	if (io_type == SPDK_BDEV_IO_TYPE_FLUSH ||
10001d3ca5c4SArtur Paszkiewicz 	    io_type == SPDK_BDEV_IO_TYPE_UNMAP) {
10011d3ca5c4SArtur Paszkiewicz 		if (raid_bdev->module->submit_null_payload_request == NULL) {
10021d3ca5c4SArtur Paszkiewicz 			return false;
10031d3ca5c4SArtur Paszkiewicz 		}
10041d3ca5c4SArtur Paszkiewicz 	}
10051d3ca5c4SArtur Paszkiewicz 
1006a193dcb8SArtur Paszkiewicz 	RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
10078d1993a5SArtur Paszkiewicz 		if (base_info->desc == NULL) {
100807fe6a43SSeth Howell 			continue;
100907fe6a43SSeth Howell 		}
101007fe6a43SSeth Howell 
10118d1993a5SArtur Paszkiewicz 		if (spdk_bdev_io_type_supported(spdk_bdev_desc_get_bdev(base_info->desc), io_type) == false) {
101207fe6a43SSeth Howell 			return false;
101307fe6a43SSeth Howell 		}
101407fe6a43SSeth Howell 	}
101507fe6a43SSeth Howell 
101607fe6a43SSeth Howell 	return true;
101707fe6a43SSeth Howell }
101807fe6a43SSeth Howell 
101907fe6a43SSeth Howell /*
102007fe6a43SSeth Howell  * brief:
102107fe6a43SSeth Howell  * raid_bdev_io_type_supported is the io_supported function for bdev function
102207fe6a43SSeth Howell  * table which returns whether the particular io type is supported or not by
102307fe6a43SSeth Howell  * raid bdev module
102407fe6a43SSeth Howell  * params:
102507fe6a43SSeth Howell  * ctx - pointer to raid bdev context
102607fe6a43SSeth Howell  * type - io type
102707fe6a43SSeth Howell  * returns:
102807fe6a43SSeth Howell  * true - io_type is supported
102907fe6a43SSeth Howell  * false - io_type is not supported
103007fe6a43SSeth Howell  */
103107fe6a43SSeth Howell static bool
103207fe6a43SSeth Howell raid_bdev_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type)
103307fe6a43SSeth Howell {
103407fe6a43SSeth Howell 	switch (io_type) {
103507fe6a43SSeth Howell 	case SPDK_BDEV_IO_TYPE_READ:
103607fe6a43SSeth Howell 	case SPDK_BDEV_IO_TYPE_WRITE:
103707fe6a43SSeth Howell 		return true;
103807fe6a43SSeth Howell 
103907fe6a43SSeth Howell 	case SPDK_BDEV_IO_TYPE_FLUSH:
104007fe6a43SSeth Howell 	case SPDK_BDEV_IO_TYPE_RESET:
104107fe6a43SSeth Howell 	case SPDK_BDEV_IO_TYPE_UNMAP:
104207fe6a43SSeth Howell 		return _raid_bdev_io_type_supported(ctx, io_type);
104307fe6a43SSeth Howell 
104407fe6a43SSeth Howell 	default:
104507fe6a43SSeth Howell 		return false;
104607fe6a43SSeth Howell 	}
104707fe6a43SSeth Howell 
104807fe6a43SSeth Howell 	return false;
104907fe6a43SSeth Howell }
105007fe6a43SSeth Howell 
105107fe6a43SSeth Howell /*
105207fe6a43SSeth Howell  * brief:
105307fe6a43SSeth Howell  * raid_bdev_get_io_channel is the get_io_channel function table pointer for
105407fe6a43SSeth Howell  * raid bdev. This is used to return the io channel for this raid bdev
105507fe6a43SSeth Howell  * params:
105607fe6a43SSeth Howell  * ctxt - pointer to raid_bdev
105707fe6a43SSeth Howell  * returns:
105807fe6a43SSeth Howell  * pointer to io channel for raid bdev
105907fe6a43SSeth Howell  */
106007fe6a43SSeth Howell static struct spdk_io_channel *
106107fe6a43SSeth Howell raid_bdev_get_io_channel(void *ctxt)
106207fe6a43SSeth Howell {
106307fe6a43SSeth Howell 	struct raid_bdev *raid_bdev = ctxt;
106407fe6a43SSeth Howell 
106507fe6a43SSeth Howell 	return spdk_get_io_channel(raid_bdev);
106607fe6a43SSeth Howell }
106707fe6a43SSeth Howell 
1068ec6d94b6SArtur Paszkiewicz void
1069ec6d94b6SArtur Paszkiewicz raid_bdev_write_info_json(struct raid_bdev *raid_bdev, struct spdk_json_write_ctx *w)
107007fe6a43SSeth Howell {
1071a193dcb8SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info;
107207fe6a43SSeth Howell 
107307fe6a43SSeth Howell 	assert(raid_bdev != NULL);
10744dd2a0d3SArtur Paszkiewicz 	assert(spdk_get_thread() == spdk_thread_get_app_thread());
107507fe6a43SSeth Howell 
107656317f62SEugene Kobyak 	spdk_json_write_named_uuid(w, "uuid", &raid_bdev->bdev.uuid);
107707fe6a43SSeth Howell 	spdk_json_write_named_uint32(w, "strip_size_kb", raid_bdev->strip_size_kb);
107846ff15a6SArtur Paszkiewicz 	spdk_json_write_named_string(w, "state", raid_bdev_state_to_str(raid_bdev->state));
1079445e667fSArtur Paszkiewicz 	spdk_json_write_named_string(w, "raid_level", raid_bdev_level_to_str(raid_bdev->level));
10803bb8256aSArtur Paszkiewicz 	spdk_json_write_named_bool(w, "superblock", raid_bdev->superblock_enabled);
108107fe6a43SSeth Howell 	spdk_json_write_named_uint32(w, "num_base_bdevs", raid_bdev->num_base_bdevs);
108207fe6a43SSeth Howell 	spdk_json_write_named_uint32(w, "num_base_bdevs_discovered", raid_bdev->num_base_bdevs_discovered);
1083255d0786SArtur Paszkiewicz 	spdk_json_write_named_uint32(w, "num_base_bdevs_operational",
1084255d0786SArtur Paszkiewicz 				     raid_bdev->num_base_bdevs_operational);
108550d58ff3SArtur Paszkiewicz 	if (raid_bdev->process) {
108650d58ff3SArtur Paszkiewicz 		struct raid_bdev_process *process = raid_bdev->process;
108750d58ff3SArtur Paszkiewicz 		uint64_t offset = process->window_offset;
108850d58ff3SArtur Paszkiewicz 
108950d58ff3SArtur Paszkiewicz 		spdk_json_write_named_object_begin(w, "process");
109050d58ff3SArtur Paszkiewicz 		spdk_json_write_name(w, "type");
109150d58ff3SArtur Paszkiewicz 		spdk_json_write_string(w, raid_bdev_process_to_str(process->type));
109250d58ff3SArtur Paszkiewicz 		spdk_json_write_named_string(w, "target", process->target->name);
109350d58ff3SArtur Paszkiewicz 		spdk_json_write_named_object_begin(w, "progress");
109450d58ff3SArtur Paszkiewicz 		spdk_json_write_named_uint64(w, "blocks", offset);
109550d58ff3SArtur Paszkiewicz 		spdk_json_write_named_uint32(w, "percent", offset * 100.0 / raid_bdev->bdev.blockcnt);
109650d58ff3SArtur Paszkiewicz 		spdk_json_write_object_end(w);
109750d58ff3SArtur Paszkiewicz 		spdk_json_write_object_end(w);
109850d58ff3SArtur Paszkiewicz 	}
109907fe6a43SSeth Howell 	spdk_json_write_name(w, "base_bdevs_list");
110007fe6a43SSeth Howell 	spdk_json_write_array_begin(w);
1101a193dcb8SArtur Paszkiewicz 	RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
1102c51db566SArtur Paszkiewicz 		spdk_json_write_object_begin(w);
1103c51db566SArtur Paszkiewicz 		spdk_json_write_name(w, "name");
1104c51db566SArtur Paszkiewicz 		if (base_info->name) {
1105c51db566SArtur Paszkiewicz 			spdk_json_write_string(w, base_info->name);
110607fe6a43SSeth Howell 		} else {
110707fe6a43SSeth Howell 			spdk_json_write_null(w);
110807fe6a43SSeth Howell 		}
110956317f62SEugene Kobyak 		spdk_json_write_named_uuid(w, "uuid", &base_info->uuid);
1110c51db566SArtur Paszkiewicz 		spdk_json_write_named_bool(w, "is_configured", base_info->is_configured);
1111c51db566SArtur Paszkiewicz 		spdk_json_write_named_uint64(w, "data_offset", base_info->data_offset);
1112c51db566SArtur Paszkiewicz 		spdk_json_write_named_uint64(w, "data_size", base_info->data_size);
1113c51db566SArtur Paszkiewicz 		spdk_json_write_object_end(w);
111407fe6a43SSeth Howell 	}
111507fe6a43SSeth Howell 	spdk_json_write_array_end(w);
1116ec6d94b6SArtur Paszkiewicz }
1117ec6d94b6SArtur Paszkiewicz 
1118ec6d94b6SArtur Paszkiewicz /*
1119ec6d94b6SArtur Paszkiewicz  * brief:
1120ec6d94b6SArtur Paszkiewicz  * raid_bdev_dump_info_json is the function table pointer for raid bdev
1121ec6d94b6SArtur Paszkiewicz  * params:
1122ec6d94b6SArtur Paszkiewicz  * ctx - pointer to raid_bdev
1123ec6d94b6SArtur Paszkiewicz  * w - pointer to json context
1124ec6d94b6SArtur Paszkiewicz  * returns:
1125ec6d94b6SArtur Paszkiewicz  * 0 - success
1126ec6d94b6SArtur Paszkiewicz  * non zero - failure
1127ec6d94b6SArtur Paszkiewicz  */
1128ec6d94b6SArtur Paszkiewicz static int
1129ec6d94b6SArtur Paszkiewicz raid_bdev_dump_info_json(void *ctx, struct spdk_json_write_ctx *w)
1130ec6d94b6SArtur Paszkiewicz {
1131ec6d94b6SArtur Paszkiewicz 	struct raid_bdev *raid_bdev = ctx;
1132ec6d94b6SArtur Paszkiewicz 
1133ec6d94b6SArtur Paszkiewicz 	SPDK_DEBUGLOG(bdev_raid, "raid_bdev_dump_config_json\n");
1134ec6d94b6SArtur Paszkiewicz 
1135ec6d94b6SArtur Paszkiewicz 	/* Dump the raid bdev configuration related information */
1136ec6d94b6SArtur Paszkiewicz 	spdk_json_write_named_object_begin(w, "raid");
1137ec6d94b6SArtur Paszkiewicz 	raid_bdev_write_info_json(raid_bdev, w);
113807fe6a43SSeth Howell 	spdk_json_write_object_end(w);
113907fe6a43SSeth Howell 
114007fe6a43SSeth Howell 	return 0;
114107fe6a43SSeth Howell }
114207fe6a43SSeth Howell 
114307fe6a43SSeth Howell /*
114407fe6a43SSeth Howell  * brief:
114507fe6a43SSeth Howell  * raid_bdev_write_config_json is the function table pointer for raid bdev
114607fe6a43SSeth Howell  * params:
114707fe6a43SSeth Howell  * bdev - pointer to spdk_bdev
114807fe6a43SSeth Howell  * w - pointer to json context
114907fe6a43SSeth Howell  * returns:
115007fe6a43SSeth Howell  * none
115107fe6a43SSeth Howell  */
115207fe6a43SSeth Howell static void
115307fe6a43SSeth Howell raid_bdev_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w)
115407fe6a43SSeth Howell {
115507fe6a43SSeth Howell 	struct raid_bdev *raid_bdev = bdev->ctxt;
1156a193dcb8SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info;
115707fe6a43SSeth Howell 
11584dd2a0d3SArtur Paszkiewicz 	assert(spdk_get_thread() == spdk_thread_get_app_thread());
11594dd2a0d3SArtur Paszkiewicz 
11603bb8256aSArtur Paszkiewicz 	if (raid_bdev->superblock_enabled) {
1161deed7d2fSArtur Paszkiewicz 		/* raid bdev configuration is stored in the superblock */
1162deed7d2fSArtur Paszkiewicz 		return;
1163deed7d2fSArtur Paszkiewicz 	}
1164deed7d2fSArtur Paszkiewicz 
116507fe6a43SSeth Howell 	spdk_json_write_object_begin(w);
116607fe6a43SSeth Howell 
1167f0731534SMaciej Wawryk 	spdk_json_write_named_string(w, "method", "bdev_raid_create");
116807fe6a43SSeth Howell 
116907fe6a43SSeth Howell 	spdk_json_write_named_object_begin(w, "params");
117007fe6a43SSeth Howell 	spdk_json_write_named_string(w, "name", bdev->name);
117156317f62SEugene Kobyak 	spdk_json_write_named_uuid(w, "uuid", &raid_bdev->bdev.uuid);
117296aff3c9SArtur Paszkiewicz 	if (raid_bdev->strip_size_kb != 0) {
1173af4fa148SWANGHAILIANG 		spdk_json_write_named_uint32(w, "strip_size_kb", raid_bdev->strip_size_kb);
117496aff3c9SArtur Paszkiewicz 	}
1175445e667fSArtur Paszkiewicz 	spdk_json_write_named_string(w, "raid_level", raid_bdev_level_to_str(raid_bdev->level));
117607fe6a43SSeth Howell 
117707fe6a43SSeth Howell 	spdk_json_write_named_array_begin(w, "base_bdevs");
1178a193dcb8SArtur Paszkiewicz 	RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
117996aff3c9SArtur Paszkiewicz 		if (base_info->name) {
118096aff3c9SArtur Paszkiewicz 			spdk_json_write_string(w, base_info->name);
118196aff3c9SArtur Paszkiewicz 		} else {
118296aff3c9SArtur Paszkiewicz 			char str[32];
118396aff3c9SArtur Paszkiewicz 
118496aff3c9SArtur Paszkiewicz 			snprintf(str, sizeof(str), "removed_base_bdev_%u", raid_bdev_base_bdev_slot(base_info));
118596aff3c9SArtur Paszkiewicz 			spdk_json_write_string(w, str);
118607fe6a43SSeth Howell 		}
118707fe6a43SSeth Howell 	}
118807fe6a43SSeth Howell 	spdk_json_write_array_end(w);
118907fe6a43SSeth Howell 	spdk_json_write_object_end(w);
119007fe6a43SSeth Howell 
119107fe6a43SSeth Howell 	spdk_json_write_object_end(w);
119207fe6a43SSeth Howell }
119307fe6a43SSeth Howell 
1194be440c01SAlexey Marchuk static int
1195be440c01SAlexey Marchuk raid_bdev_get_memory_domains(void *ctx, struct spdk_memory_domain **domains, int array_size)
1196be440c01SAlexey Marchuk {
1197be440c01SAlexey Marchuk 	struct raid_bdev *raid_bdev = ctx;
1198973b0d62SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info;
1199b42cb0e5SArtur Paszkiewicz 	int domains_count = 0, rc = 0;
1200be440c01SAlexey Marchuk 
120172672d49SArtur Paszkiewicz 	if (raid_bdev->module->memory_domains_supported == false) {
120272672d49SArtur Paszkiewicz 		return 0;
120372672d49SArtur Paszkiewicz 	}
120472672d49SArtur Paszkiewicz 
1205be440c01SAlexey Marchuk 	/* First loop to get the number of memory domains */
1206973b0d62SArtur Paszkiewicz 	RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
12076518a98dSArtur Paszkiewicz 		if (base_info->is_configured == false) {
1208b42cb0e5SArtur Paszkiewicz 			continue;
1209b42cb0e5SArtur Paszkiewicz 		}
12108d1993a5SArtur Paszkiewicz 		rc = spdk_bdev_get_memory_domains(spdk_bdev_desc_get_bdev(base_info->desc), NULL, 0);
1211be440c01SAlexey Marchuk 		if (rc < 0) {
12126518a98dSArtur Paszkiewicz 			return rc;
1213be440c01SAlexey Marchuk 		}
1214be440c01SAlexey Marchuk 		domains_count += rc;
1215be440c01SAlexey Marchuk 	}
1216be440c01SAlexey Marchuk 
1217be440c01SAlexey Marchuk 	if (!domains || array_size < domains_count) {
12186518a98dSArtur Paszkiewicz 		return domains_count;
1219be440c01SAlexey Marchuk 	}
1220be440c01SAlexey Marchuk 
1221973b0d62SArtur Paszkiewicz 	RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
12226518a98dSArtur Paszkiewicz 		if (base_info->is_configured == false) {
1223b42cb0e5SArtur Paszkiewicz 			continue;
1224b42cb0e5SArtur Paszkiewicz 		}
12258d1993a5SArtur Paszkiewicz 		rc = spdk_bdev_get_memory_domains(spdk_bdev_desc_get_bdev(base_info->desc), domains, array_size);
1226be440c01SAlexey Marchuk 		if (rc < 0) {
12276518a98dSArtur Paszkiewicz 			return rc;
1228be440c01SAlexey Marchuk 		}
1229be440c01SAlexey Marchuk 		domains += rc;
1230be440c01SAlexey Marchuk 		array_size -= rc;
1231be440c01SAlexey Marchuk 	}
1232be440c01SAlexey Marchuk 
1233be440c01SAlexey Marchuk 	return domains_count;
1234be440c01SAlexey Marchuk }
1235be440c01SAlexey Marchuk 
123607fe6a43SSeth Howell /* g_raid_bdev_fn_table is the function table for raid bdev */
123707fe6a43SSeth Howell static const struct spdk_bdev_fn_table g_raid_bdev_fn_table = {
123807fe6a43SSeth Howell 	.destruct		= raid_bdev_destruct,
123907fe6a43SSeth Howell 	.submit_request		= raid_bdev_submit_request,
124007fe6a43SSeth Howell 	.io_type_supported	= raid_bdev_io_type_supported,
124107fe6a43SSeth Howell 	.get_io_channel		= raid_bdev_get_io_channel,
124207fe6a43SSeth Howell 	.dump_info_json		= raid_bdev_dump_info_json,
124307fe6a43SSeth Howell 	.write_config_json	= raid_bdev_write_config_json,
1244be440c01SAlexey Marchuk 	.get_memory_domains	= raid_bdev_get_memory_domains,
124507fe6a43SSeth Howell };
124607fe6a43SSeth Howell 
1247dccdd1e5SArtur Paszkiewicz struct raid_bdev *
1248dccdd1e5SArtur Paszkiewicz raid_bdev_find_by_name(const char *name)
124907fe6a43SSeth Howell {
1250dccdd1e5SArtur Paszkiewicz 	struct raid_bdev *raid_bdev;
125107fe6a43SSeth Howell 
1252dccdd1e5SArtur Paszkiewicz 	TAILQ_FOREACH(raid_bdev, &g_raid_bdev_list, global_link) {
1253dccdd1e5SArtur Paszkiewicz 		if (strcmp(raid_bdev->bdev.name, name) == 0) {
1254dccdd1e5SArtur Paszkiewicz 			return raid_bdev;
125507fe6a43SSeth Howell 		}
125607fe6a43SSeth Howell 	}
125707fe6a43SSeth Howell 
1258dccdd1e5SArtur Paszkiewicz 	return NULL;
125907fe6a43SSeth Howell }
1260445e667fSArtur Paszkiewicz 
1261688de1b9SArtur Paszkiewicz static struct raid_bdev *
1262688de1b9SArtur Paszkiewicz raid_bdev_find_by_uuid(const struct spdk_uuid *uuid)
1263688de1b9SArtur Paszkiewicz {
1264688de1b9SArtur Paszkiewicz 	struct raid_bdev *raid_bdev;
1265688de1b9SArtur Paszkiewicz 
1266688de1b9SArtur Paszkiewicz 	TAILQ_FOREACH(raid_bdev, &g_raid_bdev_list, global_link) {
1267688de1b9SArtur Paszkiewicz 		if (spdk_uuid_compare(&raid_bdev->bdev.uuid, uuid) == 0) {
1268688de1b9SArtur Paszkiewicz 			return raid_bdev;
1269688de1b9SArtur Paszkiewicz 		}
1270688de1b9SArtur Paszkiewicz 	}
1271688de1b9SArtur Paszkiewicz 
1272688de1b9SArtur Paszkiewicz 	return NULL;
1273688de1b9SArtur Paszkiewicz }
1274688de1b9SArtur Paszkiewicz 
1275445e667fSArtur Paszkiewicz static struct {
1276445e667fSArtur Paszkiewicz 	const char *name;
1277445e667fSArtur Paszkiewicz 	enum raid_level value;
1278445e667fSArtur Paszkiewicz } g_raid_level_names[] = {
1279445e667fSArtur Paszkiewicz 	{ "raid0", RAID0 },
1280445e667fSArtur Paszkiewicz 	{ "0", RAID0 },
1281208f21cdSKrzysztof Smolinski 	{ "raid1", RAID1 },
1282208f21cdSKrzysztof Smolinski 	{ "1", RAID1 },
128383a4b155SArtur Paszkiewicz 	{ "raid5f", RAID5F },
128483a4b155SArtur Paszkiewicz 	{ "5f", RAID5F },
128564eebbd1Syupeng 	{ "concat", CONCAT },
1286445e667fSArtur Paszkiewicz 	{ }
1287445e667fSArtur Paszkiewicz };
1288445e667fSArtur Paszkiewicz 
12890ea6e36aSArtur Paszkiewicz const char *g_raid_state_names[] = {
12900ea6e36aSArtur Paszkiewicz 	[RAID_BDEV_STATE_ONLINE]	= "online",
12910ea6e36aSArtur Paszkiewicz 	[RAID_BDEV_STATE_CONFIGURING]	= "configuring",
12920ea6e36aSArtur Paszkiewicz 	[RAID_BDEV_STATE_OFFLINE]	= "offline",
12930ea6e36aSArtur Paszkiewicz 	[RAID_BDEV_STATE_MAX]		= NULL
129446ff15a6SArtur Paszkiewicz };
129546ff15a6SArtur Paszkiewicz 
129650d58ff3SArtur Paszkiewicz static const char *g_raid_process_type_names[] = {
129750d58ff3SArtur Paszkiewicz 	[RAID_PROCESS_NONE]	= "none",
129850d58ff3SArtur Paszkiewicz 	[RAID_PROCESS_REBUILD]	= "rebuild",
129950d58ff3SArtur Paszkiewicz 	[RAID_PROCESS_MAX]	= NULL
130050d58ff3SArtur Paszkiewicz };
130150d58ff3SArtur Paszkiewicz 
13028dd1cd21SBen Walker /* We have to use the typedef in the function declaration to appease astyle. */
13038dd1cd21SBen Walker typedef enum raid_level raid_level_t;
130446ff15a6SArtur Paszkiewicz typedef enum raid_bdev_state raid_bdev_state_t;
13058dd1cd21SBen Walker 
13068dd1cd21SBen Walker raid_level_t
130746ff15a6SArtur Paszkiewicz raid_bdev_str_to_level(const char *str)
1308445e667fSArtur Paszkiewicz {
1309445e667fSArtur Paszkiewicz 	unsigned int i;
1310445e667fSArtur Paszkiewicz 
1311a2606d4bSMaciej Szwed 	assert(str != NULL);
1312a2606d4bSMaciej Szwed 
1313445e667fSArtur Paszkiewicz 	for (i = 0; g_raid_level_names[i].name != NULL; i++) {
1314445e667fSArtur Paszkiewicz 		if (strcasecmp(g_raid_level_names[i].name, str) == 0) {
1315445e667fSArtur Paszkiewicz 			return g_raid_level_names[i].value;
1316445e667fSArtur Paszkiewicz 		}
1317445e667fSArtur Paszkiewicz 	}
1318445e667fSArtur Paszkiewicz 
1319445e667fSArtur Paszkiewicz 	return INVALID_RAID_LEVEL;
1320445e667fSArtur Paszkiewicz }
1321445e667fSArtur Paszkiewicz 
1322445e667fSArtur Paszkiewicz const char *
1323445e667fSArtur Paszkiewicz raid_bdev_level_to_str(enum raid_level level)
1324445e667fSArtur Paszkiewicz {
1325445e667fSArtur Paszkiewicz 	unsigned int i;
1326445e667fSArtur Paszkiewicz 
1327445e667fSArtur Paszkiewicz 	for (i = 0; g_raid_level_names[i].name != NULL; i++) {
1328445e667fSArtur Paszkiewicz 		if (g_raid_level_names[i].value == level) {
1329445e667fSArtur Paszkiewicz 			return g_raid_level_names[i].name;
1330445e667fSArtur Paszkiewicz 		}
1331445e667fSArtur Paszkiewicz 	}
1332445e667fSArtur Paszkiewicz 
1333445e667fSArtur Paszkiewicz 	return "";
1334445e667fSArtur Paszkiewicz }
1335445e667fSArtur Paszkiewicz 
133646ff15a6SArtur Paszkiewicz raid_bdev_state_t
133746ff15a6SArtur Paszkiewicz raid_bdev_str_to_state(const char *str)
133846ff15a6SArtur Paszkiewicz {
133946ff15a6SArtur Paszkiewicz 	unsigned int i;
134046ff15a6SArtur Paszkiewicz 
134146ff15a6SArtur Paszkiewicz 	assert(str != NULL);
134246ff15a6SArtur Paszkiewicz 
13430ea6e36aSArtur Paszkiewicz 	for (i = 0; i < RAID_BDEV_STATE_MAX; i++) {
13440ea6e36aSArtur Paszkiewicz 		if (strcasecmp(g_raid_state_names[i], str) == 0) {
13450ea6e36aSArtur Paszkiewicz 			break;
134646ff15a6SArtur Paszkiewicz 		}
134746ff15a6SArtur Paszkiewicz 	}
134846ff15a6SArtur Paszkiewicz 
13490ea6e36aSArtur Paszkiewicz 	return i;
135046ff15a6SArtur Paszkiewicz }
135146ff15a6SArtur Paszkiewicz 
135246ff15a6SArtur Paszkiewicz const char *
135346ff15a6SArtur Paszkiewicz raid_bdev_state_to_str(enum raid_bdev_state state)
135446ff15a6SArtur Paszkiewicz {
13550ea6e36aSArtur Paszkiewicz 	if (state >= RAID_BDEV_STATE_MAX) {
135646ff15a6SArtur Paszkiewicz 		return "";
135746ff15a6SArtur Paszkiewicz 	}
135846ff15a6SArtur Paszkiewicz 
13590ea6e36aSArtur Paszkiewicz 	return g_raid_state_names[state];
13600ea6e36aSArtur Paszkiewicz }
13610ea6e36aSArtur Paszkiewicz 
136250d58ff3SArtur Paszkiewicz const char *
136350d58ff3SArtur Paszkiewicz raid_bdev_process_to_str(enum raid_process_type value)
136450d58ff3SArtur Paszkiewicz {
136550d58ff3SArtur Paszkiewicz 	if (value >= RAID_PROCESS_MAX) {
136650d58ff3SArtur Paszkiewicz 		return "";
136750d58ff3SArtur Paszkiewicz 	}
136850d58ff3SArtur Paszkiewicz 
136950d58ff3SArtur Paszkiewicz 	return g_raid_process_type_names[value];
137050d58ff3SArtur Paszkiewicz }
137150d58ff3SArtur Paszkiewicz 
137207fe6a43SSeth Howell /*
137307fe6a43SSeth Howell  * brief:
137407fe6a43SSeth Howell  * raid_bdev_fini_start is called when bdev layer is starting the
137507fe6a43SSeth Howell  * shutdown process
137607fe6a43SSeth Howell  * params:
137707fe6a43SSeth Howell  * none
137807fe6a43SSeth Howell  * returns:
137907fe6a43SSeth Howell  * none
138007fe6a43SSeth Howell  */
138107fe6a43SSeth Howell static void
138207fe6a43SSeth Howell raid_bdev_fini_start(void)
138307fe6a43SSeth Howell {
1384f8465ae4SSebastian Brzezinka 	struct raid_bdev *raid_bdev;
1385f8465ae4SSebastian Brzezinka 	struct raid_base_bdev_info *base_info;
1386f8465ae4SSebastian Brzezinka 
13872172c432STomasz Zawadzki 	SPDK_DEBUGLOG(bdev_raid, "raid_bdev_fini_start\n");
1388f8465ae4SSebastian Brzezinka 
1389f8465ae4SSebastian Brzezinka 	TAILQ_FOREACH(raid_bdev, &g_raid_bdev_list, global_link) {
1390f8465ae4SSebastian Brzezinka 		if (raid_bdev->state != RAID_BDEV_STATE_ONLINE) {
1391f8465ae4SSebastian Brzezinka 			RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
1392f8465ae4SSebastian Brzezinka 				raid_bdev_free_base_bdev_resource(base_info);
1393f8465ae4SSebastian Brzezinka 			}
1394f8465ae4SSebastian Brzezinka 		}
1395f8465ae4SSebastian Brzezinka 	}
1396f8465ae4SSebastian Brzezinka 
139707fe6a43SSeth Howell 	g_shutdown_started = true;
139807fe6a43SSeth Howell }
139907fe6a43SSeth Howell 
140007fe6a43SSeth Howell /*
140107fe6a43SSeth Howell  * brief:
140207fe6a43SSeth Howell  * raid_bdev_exit is called on raid bdev module exit time by bdev layer
140307fe6a43SSeth Howell  * params:
140407fe6a43SSeth Howell  * none
140507fe6a43SSeth Howell  * returns:
140607fe6a43SSeth Howell  * none
140707fe6a43SSeth Howell  */
140807fe6a43SSeth Howell static void
140907fe6a43SSeth Howell raid_bdev_exit(void)
141007fe6a43SSeth Howell {
1411dccdd1e5SArtur Paszkiewicz 	struct raid_bdev *raid_bdev, *tmp;
141295a04949SArtur Paszkiewicz 
14132172c432STomasz Zawadzki 	SPDK_DEBUGLOG(bdev_raid, "raid_bdev_exit\n");
1414dccdd1e5SArtur Paszkiewicz 
1415dccdd1e5SArtur Paszkiewicz 	TAILQ_FOREACH_SAFE(raid_bdev, &g_raid_bdev_list, global_link, tmp) {
1416dccdd1e5SArtur Paszkiewicz 		raid_bdev_cleanup_and_free(raid_bdev);
141795a04949SArtur Paszkiewicz 	}
141807fe6a43SSeth Howell }
141907fe6a43SSeth Howell 
1420f39350beSArtur Paszkiewicz static void
1421f39350beSArtur Paszkiewicz raid_bdev_opts_config_json(struct spdk_json_write_ctx *w)
1422f39350beSArtur Paszkiewicz {
1423f39350beSArtur Paszkiewicz 	spdk_json_write_object_begin(w);
1424f39350beSArtur Paszkiewicz 
1425f39350beSArtur Paszkiewicz 	spdk_json_write_named_string(w, "method", "bdev_raid_set_options");
1426f39350beSArtur Paszkiewicz 
1427f39350beSArtur Paszkiewicz 	spdk_json_write_named_object_begin(w, "params");
1428f39350beSArtur Paszkiewicz 	spdk_json_write_named_uint32(w, "process_window_size_kb", g_opts.process_window_size_kb);
142989fd1730Sxupeng9 	spdk_json_write_named_uint32(w, "process_max_bandwidth_mb_sec",
143089fd1730Sxupeng9 				     g_opts.process_max_bandwidth_mb_sec);
1431f39350beSArtur Paszkiewicz 	spdk_json_write_object_end(w);
1432f39350beSArtur Paszkiewicz 
1433f39350beSArtur Paszkiewicz 	spdk_json_write_object_end(w);
1434f39350beSArtur Paszkiewicz }
1435f39350beSArtur Paszkiewicz 
1436f39350beSArtur Paszkiewicz static int
1437f39350beSArtur Paszkiewicz raid_bdev_config_json(struct spdk_json_write_ctx *w)
1438f39350beSArtur Paszkiewicz {
1439f39350beSArtur Paszkiewicz 	raid_bdev_opts_config_json(w);
1440f39350beSArtur Paszkiewicz 
1441f39350beSArtur Paszkiewicz 	return 0;
1442f39350beSArtur Paszkiewicz }
1443f39350beSArtur Paszkiewicz 
144407fe6a43SSeth Howell /*
144507fe6a43SSeth Howell  * brief:
144607fe6a43SSeth Howell  * raid_bdev_get_ctx_size is used to return the context size of bdev_io for raid
144707fe6a43SSeth Howell  * module
144807fe6a43SSeth Howell  * params:
144907fe6a43SSeth Howell  * none
145007fe6a43SSeth Howell  * returns:
145107fe6a43SSeth Howell  * size of spdk_bdev_io context for raid
145207fe6a43SSeth Howell  */
145307fe6a43SSeth Howell static int
145407fe6a43SSeth Howell raid_bdev_get_ctx_size(void)
145507fe6a43SSeth Howell {
14562172c432STomasz Zawadzki 	SPDK_DEBUGLOG(bdev_raid, "raid_bdev_get_ctx_size\n");
145707fe6a43SSeth Howell 	return sizeof(struct raid_bdev_io);
145807fe6a43SSeth Howell }
145907fe6a43SSeth Howell 
146007fe6a43SSeth Howell static struct spdk_bdev_module g_raid_if = {
146107fe6a43SSeth Howell 	.name = "raid",
146207fe6a43SSeth Howell 	.module_init = raid_bdev_init,
146307fe6a43SSeth Howell 	.fini_start = raid_bdev_fini_start,
146407fe6a43SSeth Howell 	.module_fini = raid_bdev_exit,
1465f39350beSArtur Paszkiewicz 	.config_json = raid_bdev_config_json,
146607fe6a43SSeth Howell 	.get_ctx_size = raid_bdev_get_ctx_size,
14678a6bb6a8SArtur Paszkiewicz 	.examine_disk = raid_bdev_examine,
146807fe6a43SSeth Howell 	.async_init = false,
146907fe6a43SSeth Howell 	.async_fini = false,
147007fe6a43SSeth Howell };
147107fe6a43SSeth Howell SPDK_BDEV_MODULE_REGISTER(raid, &g_raid_if)
147207fe6a43SSeth Howell 
147307fe6a43SSeth Howell /*
147407fe6a43SSeth Howell  * brief:
147507fe6a43SSeth Howell  * raid_bdev_init is the initialization function for raid bdev module
147607fe6a43SSeth Howell  * params:
147707fe6a43SSeth Howell  * none
147807fe6a43SSeth Howell  * returns:
147907fe6a43SSeth Howell  * 0 - success
148007fe6a43SSeth Howell  * non zero - failure
148107fe6a43SSeth Howell  */
148207fe6a43SSeth Howell static int
148307fe6a43SSeth Howell raid_bdev_init(void)
148407fe6a43SSeth Howell {
148507fe6a43SSeth Howell 	return 0;
148607fe6a43SSeth Howell }
148707fe6a43SSeth Howell 
148877b8f7b6SArtur Paszkiewicz static int
148977b8f7b6SArtur Paszkiewicz _raid_bdev_create(const char *name, uint32_t strip_size, uint8_t num_base_bdevs,
1490deed7d2fSArtur Paszkiewicz 		  enum raid_level level, bool superblock_enabled, const struct spdk_uuid *uuid,
1491deed7d2fSArtur Paszkiewicz 		  struct raid_bdev **raid_bdev_out)
149207fe6a43SSeth Howell {
149307fe6a43SSeth Howell 	struct raid_bdev *raid_bdev;
149407fe6a43SSeth Howell 	struct spdk_bdev *raid_bdev_gen;
14950a5194faSArtur Paszkiewicz 	struct raid_bdev_module *module;
149626861b70SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info;
1497ad94094fSKrzysztof Smolinski 	uint8_t min_operational;
14980a5194faSArtur Paszkiewicz 
149977b8f7b6SArtur Paszkiewicz 	if (strnlen(name, RAID_BDEV_SB_NAME_SIZE) == RAID_BDEV_SB_NAME_SIZE) {
150077b8f7b6SArtur Paszkiewicz 		SPDK_ERRLOG("Raid bdev name '%s' exceeds %d characters\n", name, RAID_BDEV_SB_NAME_SIZE - 1);
150177b8f7b6SArtur Paszkiewicz 		return -EINVAL;
150277b8f7b6SArtur Paszkiewicz 	}
150377b8f7b6SArtur Paszkiewicz 
1504dccdd1e5SArtur Paszkiewicz 	if (raid_bdev_find_by_name(name) != NULL) {
1505dccdd1e5SArtur Paszkiewicz 		SPDK_ERRLOG("Duplicate raid bdev name found: %s\n", name);
1506dccdd1e5SArtur Paszkiewicz 		return -EEXIST;
1507dccdd1e5SArtur Paszkiewicz 	}
1508dccdd1e5SArtur Paszkiewicz 
1509208f21cdSKrzysztof Smolinski 	if (level == RAID1) {
1510208f21cdSKrzysztof Smolinski 		if (strip_size != 0) {
1511208f21cdSKrzysztof Smolinski 			SPDK_ERRLOG("Strip size is not supported by raid1\n");
1512208f21cdSKrzysztof Smolinski 			return -EINVAL;
1513208f21cdSKrzysztof Smolinski 		}
1514208f21cdSKrzysztof Smolinski 	} else if (spdk_u32_is_pow2(strip_size) == false) {
1515dccdd1e5SArtur Paszkiewicz 		SPDK_ERRLOG("Invalid strip size %" PRIu32 "\n", strip_size);
1516dccdd1e5SArtur Paszkiewicz 		return -EINVAL;
1517dccdd1e5SArtur Paszkiewicz 	}
1518dccdd1e5SArtur Paszkiewicz 
1519dccdd1e5SArtur Paszkiewicz 	module = raid_bdev_module_find(level);
15200a5194faSArtur Paszkiewicz 	if (module == NULL) {
1521dccdd1e5SArtur Paszkiewicz 		SPDK_ERRLOG("Unsupported raid level '%d'\n", level);
15220a5194faSArtur Paszkiewicz 		return -EINVAL;
15230a5194faSArtur Paszkiewicz 	}
15240a5194faSArtur Paszkiewicz 
15250a5194faSArtur Paszkiewicz 	assert(module->base_bdevs_min != 0);
1526dccdd1e5SArtur Paszkiewicz 	if (num_base_bdevs < module->base_bdevs_min) {
15270a5194faSArtur Paszkiewicz 		SPDK_ERRLOG("At least %u base devices required for %s\n",
15280a5194faSArtur Paszkiewicz 			    module->base_bdevs_min,
1529dccdd1e5SArtur Paszkiewicz 			    raid_bdev_level_to_str(level));
15300a5194faSArtur Paszkiewicz 		return -EINVAL;
15310a5194faSArtur Paszkiewicz 	}
153207fe6a43SSeth Howell 
1533ad94094fSKrzysztof Smolinski 	switch (module->base_bdevs_constraint.type) {
1534ad94094fSKrzysztof Smolinski 	case CONSTRAINT_MAX_BASE_BDEVS_REMOVED:
1535ad94094fSKrzysztof Smolinski 		min_operational = num_base_bdevs - module->base_bdevs_constraint.value;
1536ad94094fSKrzysztof Smolinski 		break;
1537ad94094fSKrzysztof Smolinski 	case CONSTRAINT_MIN_BASE_BDEVS_OPERATIONAL:
1538ad94094fSKrzysztof Smolinski 		min_operational = module->base_bdevs_constraint.value;
1539ad94094fSKrzysztof Smolinski 		break;
1540ad94094fSKrzysztof Smolinski 	case CONSTRAINT_UNSET:
1541ad94094fSKrzysztof Smolinski 		if (module->base_bdevs_constraint.value != 0) {
1542ad94094fSKrzysztof Smolinski 			SPDK_ERRLOG("Unexpected constraint value '%u' provided for raid bdev '%s'.\n",
1543ad94094fSKrzysztof Smolinski 				    (uint8_t)module->base_bdevs_constraint.value, name);
1544ad94094fSKrzysztof Smolinski 			return -EINVAL;
1545ad94094fSKrzysztof Smolinski 		}
1546ad94094fSKrzysztof Smolinski 		min_operational = num_base_bdevs;
1547ad94094fSKrzysztof Smolinski 		break;
1548ad94094fSKrzysztof Smolinski 	default:
1549ad94094fSKrzysztof Smolinski 		SPDK_ERRLOG("Unrecognised constraint type '%u' in module for raid level '%s'.\n",
1550ad94094fSKrzysztof Smolinski 			    (uint8_t)module->base_bdevs_constraint.type,
1551ad94094fSKrzysztof Smolinski 			    raid_bdev_level_to_str(module->level));
1552ad94094fSKrzysztof Smolinski 		return -EINVAL;
1553ad94094fSKrzysztof Smolinski 	};
1554ad94094fSKrzysztof Smolinski 
1555ad94094fSKrzysztof Smolinski 	if (min_operational == 0 || min_operational > num_base_bdevs) {
1556ad94094fSKrzysztof Smolinski 		SPDK_ERRLOG("Wrong constraint value for raid level '%s'.\n",
1557ad94094fSKrzysztof Smolinski 			    raid_bdev_level_to_str(module->level));
1558ad94094fSKrzysztof Smolinski 		return -EINVAL;
1559ad94094fSKrzysztof Smolinski 	}
1560ad94094fSKrzysztof Smolinski 
156107fe6a43SSeth Howell 	raid_bdev = calloc(1, sizeof(*raid_bdev));
156207fe6a43SSeth Howell 	if (!raid_bdev) {
156307fe6a43SSeth Howell 		SPDK_ERRLOG("Unable to allocate memory for raid bdev\n");
156407fe6a43SSeth Howell 		return -ENOMEM;
156507fe6a43SSeth Howell 	}
156607fe6a43SSeth Howell 
15670a5194faSArtur Paszkiewicz 	raid_bdev->module = module;
1568dccdd1e5SArtur Paszkiewicz 	raid_bdev->num_base_bdevs = num_base_bdevs;
156907fe6a43SSeth Howell 	raid_bdev->base_bdev_info = calloc(raid_bdev->num_base_bdevs,
157007fe6a43SSeth Howell 					   sizeof(struct raid_base_bdev_info));
157107fe6a43SSeth Howell 	if (!raid_bdev->base_bdev_info) {
157207fe6a43SSeth Howell 		SPDK_ERRLOG("Unable able to allocate base bdev info\n");
1573fbdb05f0SArtur Paszkiewicz 		raid_bdev_free(raid_bdev);
157407fe6a43SSeth Howell 		return -ENOMEM;
157507fe6a43SSeth Howell 	}
157607fe6a43SSeth Howell 
157726861b70SArtur Paszkiewicz 	RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
157826861b70SArtur Paszkiewicz 		base_info->raid_bdev = raid_bdev;
157926861b70SArtur Paszkiewicz 	}
158026861b70SArtur Paszkiewicz 
158107fe6a43SSeth Howell 	/* strip_size_kb is from the rpc param.  strip_size is in blocks and used
158217f7cf9bSpaul luse 	 * internally and set later.
158307fe6a43SSeth Howell 	 */
158407fe6a43SSeth Howell 	raid_bdev->strip_size = 0;
1585dccdd1e5SArtur Paszkiewicz 	raid_bdev->strip_size_kb = strip_size;
158607fe6a43SSeth Howell 	raid_bdev->state = RAID_BDEV_STATE_CONFIGURING;
1587dccdd1e5SArtur Paszkiewicz 	raid_bdev->level = level;
1588ad94094fSKrzysztof Smolinski 	raid_bdev->min_base_bdevs_operational = min_operational;
15893bb8256aSArtur Paszkiewicz 	raid_bdev->superblock_enabled = superblock_enabled;
159077b8f7b6SArtur Paszkiewicz 
159107fe6a43SSeth Howell 	raid_bdev_gen = &raid_bdev->bdev;
159207fe6a43SSeth Howell 
1593dccdd1e5SArtur Paszkiewicz 	raid_bdev_gen->name = strdup(name);
159407fe6a43SSeth Howell 	if (!raid_bdev_gen->name) {
159507fe6a43SSeth Howell 		SPDK_ERRLOG("Unable to allocate name for raid\n");
1596fbdb05f0SArtur Paszkiewicz 		raid_bdev_free(raid_bdev);
159707fe6a43SSeth Howell 		return -ENOMEM;
159807fe6a43SSeth Howell 	}
159907fe6a43SSeth Howell 
160007fe6a43SSeth Howell 	raid_bdev_gen->product_name = "Raid Volume";
160107fe6a43SSeth Howell 	raid_bdev_gen->ctxt = raid_bdev;
160207fe6a43SSeth Howell 	raid_bdev_gen->fn_table = &g_raid_bdev_fn_table;
160307fe6a43SSeth Howell 	raid_bdev_gen->module = &g_raid_if;
160407fe6a43SSeth Howell 	raid_bdev_gen->write_cache = 0;
16051db41324SKrzysztof Karas 	spdk_uuid_copy(&raid_bdev_gen->uuid, uuid);
16061db41324SKrzysztof Karas 
160707fe6a43SSeth Howell 	TAILQ_INSERT_TAIL(&g_raid_bdev_list, raid_bdev, global_link);
160807fe6a43SSeth Howell 
1609dccdd1e5SArtur Paszkiewicz 	*raid_bdev_out = raid_bdev;
161007fe6a43SSeth Howell 
161107fe6a43SSeth Howell 	return 0;
161207fe6a43SSeth Howell }
161307fe6a43SSeth Howell 
161407fe6a43SSeth Howell /*
161507fe6a43SSeth Howell  * brief:
161677b8f7b6SArtur Paszkiewicz  * raid_bdev_create allocates raid bdev based on passed configuration
161777b8f7b6SArtur Paszkiewicz  * params:
161877b8f7b6SArtur Paszkiewicz  * name - name for raid bdev
161977b8f7b6SArtur Paszkiewicz  * strip_size - strip size in KB
162077b8f7b6SArtur Paszkiewicz  * num_base_bdevs - number of base bdevs
162177b8f7b6SArtur Paszkiewicz  * level - raid level
162277b8f7b6SArtur Paszkiewicz  * superblock_enabled - true if raid should have superblock
162377b8f7b6SArtur Paszkiewicz  * uuid - uuid to set for the bdev
162477b8f7b6SArtur Paszkiewicz  * raid_bdev_out - the created raid bdev
162577b8f7b6SArtur Paszkiewicz  * returns:
162677b8f7b6SArtur Paszkiewicz  * 0 - success
162777b8f7b6SArtur Paszkiewicz  * non zero - failure
162877b8f7b6SArtur Paszkiewicz  */
162977b8f7b6SArtur Paszkiewicz int
163077b8f7b6SArtur Paszkiewicz raid_bdev_create(const char *name, uint32_t strip_size, uint8_t num_base_bdevs,
163177b8f7b6SArtur Paszkiewicz 		 enum raid_level level, bool superblock_enabled, const struct spdk_uuid *uuid,
163277b8f7b6SArtur Paszkiewicz 		 struct raid_bdev **raid_bdev_out)
163377b8f7b6SArtur Paszkiewicz {
163477b8f7b6SArtur Paszkiewicz 	struct raid_bdev *raid_bdev;
163577b8f7b6SArtur Paszkiewicz 	int rc;
163677b8f7b6SArtur Paszkiewicz 
163777b8f7b6SArtur Paszkiewicz 	assert(uuid != NULL);
163877b8f7b6SArtur Paszkiewicz 
163977b8f7b6SArtur Paszkiewicz 	rc = _raid_bdev_create(name, strip_size, num_base_bdevs, level, superblock_enabled, uuid,
164077b8f7b6SArtur Paszkiewicz 			       &raid_bdev);
164177b8f7b6SArtur Paszkiewicz 	if (rc != 0) {
164277b8f7b6SArtur Paszkiewicz 		return rc;
164377b8f7b6SArtur Paszkiewicz 	}
164477b8f7b6SArtur Paszkiewicz 
164577b8f7b6SArtur Paszkiewicz 	if (superblock_enabled && spdk_uuid_is_null(uuid)) {
164677b8f7b6SArtur Paszkiewicz 		/* we need to have the uuid to store in the superblock before the bdev is registered */
164777b8f7b6SArtur Paszkiewicz 		spdk_uuid_generate(&raid_bdev->bdev.uuid);
164877b8f7b6SArtur Paszkiewicz 	}
164977b8f7b6SArtur Paszkiewicz 
1650255d0786SArtur Paszkiewicz 	raid_bdev->num_base_bdevs_operational = num_base_bdevs;
1651255d0786SArtur Paszkiewicz 
165277b8f7b6SArtur Paszkiewicz 	*raid_bdev_out = raid_bdev;
165377b8f7b6SArtur Paszkiewicz 
165477b8f7b6SArtur Paszkiewicz 	return 0;
165577b8f7b6SArtur Paszkiewicz }
165677b8f7b6SArtur Paszkiewicz 
165777b8f7b6SArtur Paszkiewicz static void
16589d2b7b41SArtur Paszkiewicz _raid_bdev_unregistering_cont(void *ctx)
16599d2b7b41SArtur Paszkiewicz {
16609d2b7b41SArtur Paszkiewicz 	struct raid_bdev *raid_bdev = ctx;
16619d2b7b41SArtur Paszkiewicz 
16629d2b7b41SArtur Paszkiewicz 	spdk_bdev_close(raid_bdev->self_desc);
16639d2b7b41SArtur Paszkiewicz 	raid_bdev->self_desc = NULL;
16649d2b7b41SArtur Paszkiewicz }
16659d2b7b41SArtur Paszkiewicz 
16669d2b7b41SArtur Paszkiewicz static void
16679d2b7b41SArtur Paszkiewicz raid_bdev_unregistering_cont(void *ctx)
16689d2b7b41SArtur Paszkiewicz {
16699d2b7b41SArtur Paszkiewicz 	spdk_thread_exec_msg(spdk_thread_get_app_thread(), _raid_bdev_unregistering_cont, ctx);
16709d2b7b41SArtur Paszkiewicz }
16719d2b7b41SArtur Paszkiewicz 
16729d2b7b41SArtur Paszkiewicz static int
16739d2b7b41SArtur Paszkiewicz raid_bdev_process_add_finish_action(struct raid_bdev_process *process, spdk_msg_fn cb, void *cb_ctx)
16749d2b7b41SArtur Paszkiewicz {
16759d2b7b41SArtur Paszkiewicz 	struct raid_process_finish_action *finish_action;
16769d2b7b41SArtur Paszkiewicz 
16779d2b7b41SArtur Paszkiewicz 	assert(spdk_get_thread() == process->thread);
16789d2b7b41SArtur Paszkiewicz 	assert(process->state < RAID_PROCESS_STATE_STOPPED);
16799d2b7b41SArtur Paszkiewicz 
16809d2b7b41SArtur Paszkiewicz 	finish_action = calloc(1, sizeof(*finish_action));
16819d2b7b41SArtur Paszkiewicz 	if (finish_action == NULL) {
16829d2b7b41SArtur Paszkiewicz 		return -ENOMEM;
16839d2b7b41SArtur Paszkiewicz 	}
16849d2b7b41SArtur Paszkiewicz 
16859d2b7b41SArtur Paszkiewicz 	finish_action->cb = cb;
16869d2b7b41SArtur Paszkiewicz 	finish_action->cb_ctx = cb_ctx;
16879d2b7b41SArtur Paszkiewicz 
16889d2b7b41SArtur Paszkiewicz 	TAILQ_INSERT_TAIL(&process->finish_actions, finish_action, link);
16899d2b7b41SArtur Paszkiewicz 
16909d2b7b41SArtur Paszkiewicz 	return 0;
16919d2b7b41SArtur Paszkiewicz }
16929d2b7b41SArtur Paszkiewicz 
16939d2b7b41SArtur Paszkiewicz static void
16949d2b7b41SArtur Paszkiewicz raid_bdev_unregistering_stop_process(void *ctx)
16959d2b7b41SArtur Paszkiewicz {
16969d2b7b41SArtur Paszkiewicz 	struct raid_bdev_process *process = ctx;
16979d2b7b41SArtur Paszkiewicz 	struct raid_bdev *raid_bdev = process->raid_bdev;
16989d2b7b41SArtur Paszkiewicz 	int rc;
16999d2b7b41SArtur Paszkiewicz 
17009d2b7b41SArtur Paszkiewicz 	process->state = RAID_PROCESS_STATE_STOPPING;
17019d2b7b41SArtur Paszkiewicz 	if (process->status == 0) {
17029d2b7b41SArtur Paszkiewicz 		process->status = -ECANCELED;
17039d2b7b41SArtur Paszkiewicz 	}
17049d2b7b41SArtur Paszkiewicz 
17059d2b7b41SArtur Paszkiewicz 	rc = raid_bdev_process_add_finish_action(process, raid_bdev_unregistering_cont, raid_bdev);
17069d2b7b41SArtur Paszkiewicz 	if (rc != 0) {
17079d2b7b41SArtur Paszkiewicz 		SPDK_ERRLOG("Failed to add raid bdev '%s' process finish action: %s\n",
17089d2b7b41SArtur Paszkiewicz 			    raid_bdev->bdev.name, spdk_strerror(-rc));
17099d2b7b41SArtur Paszkiewicz 	}
17109d2b7b41SArtur Paszkiewicz }
17119d2b7b41SArtur Paszkiewicz 
17129d2b7b41SArtur Paszkiewicz static void
17139d2b7b41SArtur Paszkiewicz raid_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *event_ctx)
17149d2b7b41SArtur Paszkiewicz {
17159d2b7b41SArtur Paszkiewicz 	struct raid_bdev *raid_bdev = event_ctx;
17169d2b7b41SArtur Paszkiewicz 
17179b61146fSArtur Paszkiewicz 	if (type == SPDK_BDEV_EVENT_REMOVE) {
17189d2b7b41SArtur Paszkiewicz 		if (raid_bdev->process != NULL) {
17199d2b7b41SArtur Paszkiewicz 			spdk_thread_send_msg(raid_bdev->process->thread, raid_bdev_unregistering_stop_process,
17209d2b7b41SArtur Paszkiewicz 					     raid_bdev->process);
17219d2b7b41SArtur Paszkiewicz 		} else {
17229d2b7b41SArtur Paszkiewicz 			raid_bdev_unregistering_cont(raid_bdev);
17239d2b7b41SArtur Paszkiewicz 		}
17249d2b7b41SArtur Paszkiewicz 	}
17259d2b7b41SArtur Paszkiewicz }
17269d2b7b41SArtur Paszkiewicz 
17279d2b7b41SArtur Paszkiewicz static void
172877b8f7b6SArtur Paszkiewicz raid_bdev_configure_cont(struct raid_bdev *raid_bdev)
172977b8f7b6SArtur Paszkiewicz {
173077b8f7b6SArtur Paszkiewicz 	struct spdk_bdev *raid_bdev_gen = &raid_bdev->bdev;
173177b8f7b6SArtur Paszkiewicz 	int rc;
173277b8f7b6SArtur Paszkiewicz 
173377b8f7b6SArtur Paszkiewicz 	raid_bdev->state = RAID_BDEV_STATE_ONLINE;
173477b8f7b6SArtur Paszkiewicz 	SPDK_DEBUGLOG(bdev_raid, "io device register %p\n", raid_bdev);
173577b8f7b6SArtur Paszkiewicz 	SPDK_DEBUGLOG(bdev_raid, "blockcnt %" PRIu64 ", blocklen %u\n",
173677b8f7b6SArtur Paszkiewicz 		      raid_bdev_gen->blockcnt, raid_bdev_gen->blocklen);
173777b8f7b6SArtur Paszkiewicz 	spdk_io_device_register(raid_bdev, raid_bdev_create_cb, raid_bdev_destroy_cb,
173877b8f7b6SArtur Paszkiewicz 				sizeof(struct raid_bdev_io_channel),
173977b8f7b6SArtur Paszkiewicz 				raid_bdev_gen->name);
174077b8f7b6SArtur Paszkiewicz 	rc = spdk_bdev_register(raid_bdev_gen);
174177b8f7b6SArtur Paszkiewicz 	if (rc != 0) {
17429d2b7b41SArtur Paszkiewicz 		SPDK_ERRLOG("Failed to register raid bdev '%s': %s\n",
17439d2b7b41SArtur Paszkiewicz 			    raid_bdev_gen->name, spdk_strerror(-rc));
17445558f3f5SArtur Paszkiewicz 		goto out;
17459d2b7b41SArtur Paszkiewicz 	}
17469d2b7b41SArtur Paszkiewicz 
17479d2b7b41SArtur Paszkiewicz 	/*
17489d2b7b41SArtur Paszkiewicz 	 * Open the bdev internally to delay unregistering if we need to stop a background process
17499d2b7b41SArtur Paszkiewicz 	 * first. The process may still need to unquiesce a range but it will fail because the
17509d2b7b41SArtur Paszkiewicz 	 * bdev's internal.spinlock is destroyed by the time the destruct callback is reached.
17519d2b7b41SArtur Paszkiewicz 	 * During application shutdown, bdevs automatically get unregistered by the bdev layer
17529d2b7b41SArtur Paszkiewicz 	 * so this is the only way currently to do this correctly.
17539d2b7b41SArtur Paszkiewicz 	 * TODO: try to handle this correctly in bdev layer instead.
17549d2b7b41SArtur Paszkiewicz 	 */
17559d2b7b41SArtur Paszkiewicz 	rc = spdk_bdev_open_ext(raid_bdev_gen->name, false, raid_bdev_event_cb, raid_bdev,
17569d2b7b41SArtur Paszkiewicz 				&raid_bdev->self_desc);
17579d2b7b41SArtur Paszkiewicz 	if (rc != 0) {
17589d2b7b41SArtur Paszkiewicz 		SPDK_ERRLOG("Failed to open raid bdev '%s': %s\n",
17599d2b7b41SArtur Paszkiewicz 			    raid_bdev_gen->name, spdk_strerror(-rc));
17609d2b7b41SArtur Paszkiewicz 		spdk_bdev_unregister(raid_bdev_gen, NULL, NULL);
17615558f3f5SArtur Paszkiewicz 		goto out;
17629d2b7b41SArtur Paszkiewicz 	}
17639d2b7b41SArtur Paszkiewicz 
17649d2b7b41SArtur Paszkiewicz 	SPDK_DEBUGLOG(bdev_raid, "raid bdev generic %p\n", raid_bdev_gen);
17659d2b7b41SArtur Paszkiewicz 	SPDK_DEBUGLOG(bdev_raid, "raid bdev is created with name %s, raid_bdev %p\n",
17669d2b7b41SArtur Paszkiewicz 		      raid_bdev_gen->name, raid_bdev);
17675558f3f5SArtur Paszkiewicz out:
17685558f3f5SArtur Paszkiewicz 	if (rc != 0) {
176977b8f7b6SArtur Paszkiewicz 		if (raid_bdev->module->stop != NULL) {
177077b8f7b6SArtur Paszkiewicz 			raid_bdev->module->stop(raid_bdev);
177177b8f7b6SArtur Paszkiewicz 		}
177277b8f7b6SArtur Paszkiewicz 		spdk_io_device_unregister(raid_bdev, NULL);
177377b8f7b6SArtur Paszkiewicz 		raid_bdev->state = RAID_BDEV_STATE_CONFIGURING;
177477b8f7b6SArtur Paszkiewicz 	}
177577b8f7b6SArtur Paszkiewicz 
17765558f3f5SArtur Paszkiewicz 	if (raid_bdev->configure_cb != NULL) {
17775558f3f5SArtur Paszkiewicz 		raid_bdev->configure_cb(raid_bdev->configure_cb_ctx, rc);
17785558f3f5SArtur Paszkiewicz 		raid_bdev->configure_cb = NULL;
17795558f3f5SArtur Paszkiewicz 	}
17805558f3f5SArtur Paszkiewicz }
17815558f3f5SArtur Paszkiewicz 
178277b8f7b6SArtur Paszkiewicz static void
178377b8f7b6SArtur Paszkiewicz raid_bdev_configure_write_sb_cb(int status, struct raid_bdev *raid_bdev, void *ctx)
178477b8f7b6SArtur Paszkiewicz {
178577b8f7b6SArtur Paszkiewicz 	if (status == 0) {
178677b8f7b6SArtur Paszkiewicz 		raid_bdev_configure_cont(raid_bdev);
178777b8f7b6SArtur Paszkiewicz 	} else {
178877b8f7b6SArtur Paszkiewicz 		SPDK_ERRLOG("Failed to write raid bdev '%s' superblock: %s\n",
178977b8f7b6SArtur Paszkiewicz 			    raid_bdev->bdev.name, spdk_strerror(-status));
179077b8f7b6SArtur Paszkiewicz 		if (raid_bdev->module->stop != NULL) {
179177b8f7b6SArtur Paszkiewicz 			raid_bdev->module->stop(raid_bdev);
179277b8f7b6SArtur Paszkiewicz 		}
17935558f3f5SArtur Paszkiewicz 		if (raid_bdev->configure_cb != NULL) {
17945558f3f5SArtur Paszkiewicz 			raid_bdev->configure_cb(raid_bdev->configure_cb_ctx, status);
17955558f3f5SArtur Paszkiewicz 			raid_bdev->configure_cb = NULL;
17965558f3f5SArtur Paszkiewicz 		}
179777b8f7b6SArtur Paszkiewicz 	}
179877b8f7b6SArtur Paszkiewicz }
179977b8f7b6SArtur Paszkiewicz 
1800357c038cSKrzysztof Smolinski /*
1801357c038cSKrzysztof Smolinski  * brief:
180207fe6a43SSeth Howell  * If raid bdev config is complete, then only register the raid bdev to
180307fe6a43SSeth Howell  * bdev layer and remove this raid bdev from configuring list and
180407fe6a43SSeth Howell  * insert the raid bdev to configured list
180507fe6a43SSeth Howell  * params:
180607fe6a43SSeth Howell  * raid_bdev - pointer to raid bdev
180707fe6a43SSeth Howell  * returns:
180807fe6a43SSeth Howell  * 0 - success
180907fe6a43SSeth Howell  * non zero - failure
181007fe6a43SSeth Howell  */
181107fe6a43SSeth Howell static int
18125558f3f5SArtur Paszkiewicz raid_bdev_configure(struct raid_bdev *raid_bdev, raid_bdev_configure_cb cb, void *cb_ctx)
181307fe6a43SSeth Howell {
1814bb374988SArtur Paszkiewicz 	uint32_t data_block_size = spdk_bdev_get_data_block_size(&raid_bdev->bdev);
1815895d8b56SArtur Paszkiewicz 	int rc;
181607fe6a43SSeth Howell 
181794ea8754SArtur Paszkiewicz 	assert(raid_bdev->state == RAID_BDEV_STATE_CONFIGURING);
1818255d0786SArtur Paszkiewicz 	assert(raid_bdev->num_base_bdevs_discovered == raid_bdev->num_base_bdevs_operational);
1819895d8b56SArtur Paszkiewicz 	assert(raid_bdev->bdev.blocklen > 0);
182007fe6a43SSeth Howell 
182107fe6a43SSeth Howell 	/* The strip_size_kb is read in from user in KB. Convert to blocks here for
182207fe6a43SSeth Howell 	 * internal use.
182307fe6a43SSeth Howell 	 */
1824bb374988SArtur Paszkiewicz 	raid_bdev->strip_size = (raid_bdev->strip_size_kb * 1024) / data_block_size;
182531ce6cd8SArtur Paszkiewicz 	if (raid_bdev->strip_size == 0 && raid_bdev->level != RAID1) {
182631ce6cd8SArtur Paszkiewicz 		SPDK_ERRLOG("Strip size cannot be smaller than the device block size\n");
182731ce6cd8SArtur Paszkiewicz 		return -EINVAL;
182831ce6cd8SArtur Paszkiewicz 	}
182907fe6a43SSeth Howell 	raid_bdev->strip_size_shift = spdk_u32log2(raid_bdev->strip_size);
1830357c038cSKrzysztof Smolinski 
18310b4ca522SArtur Paszkiewicz 	rc = raid_bdev->module->start(raid_bdev);
18320b4ca522SArtur Paszkiewicz 	if (rc != 0) {
18330b4ca522SArtur Paszkiewicz 		SPDK_ERRLOG("raid module startup callback failed\n");
18340b4ca522SArtur Paszkiewicz 		return rc;
183507fe6a43SSeth Howell 	}
183677b8f7b6SArtur Paszkiewicz 
18375558f3f5SArtur Paszkiewicz 	assert(raid_bdev->configure_cb == NULL);
18385558f3f5SArtur Paszkiewicz 	raid_bdev->configure_cb = cb;
18395558f3f5SArtur Paszkiewicz 	raid_bdev->configure_cb_ctx = cb_ctx;
18405558f3f5SArtur Paszkiewicz 
18413bb8256aSArtur Paszkiewicz 	if (raid_bdev->superblock_enabled) {
1842c25b80e2SArtur Paszkiewicz 		if (raid_bdev->sb == NULL) {
1843c25b80e2SArtur Paszkiewicz 			rc = raid_bdev_alloc_superblock(raid_bdev, data_block_size);
1844c25b80e2SArtur Paszkiewicz 			if (rc == 0) {
184577b8f7b6SArtur Paszkiewicz 				raid_bdev_init_superblock(raid_bdev);
1846c25b80e2SArtur Paszkiewicz 			}
18478a6bb6a8SArtur Paszkiewicz 		} else {
18488a6bb6a8SArtur Paszkiewicz 			assert(spdk_uuid_compare(&raid_bdev->sb->uuid, &raid_bdev->bdev.uuid) == 0);
1849bb374988SArtur Paszkiewicz 			if (raid_bdev->sb->block_size != data_block_size) {
18508a6bb6a8SArtur Paszkiewicz 				SPDK_ERRLOG("blocklen does not match value in superblock\n");
18518a6bb6a8SArtur Paszkiewicz 				rc = -EINVAL;
18528a6bb6a8SArtur Paszkiewicz 			}
18538a6bb6a8SArtur Paszkiewicz 			if (raid_bdev->sb->raid_size != raid_bdev->bdev.blockcnt) {
18548a6bb6a8SArtur Paszkiewicz 				SPDK_ERRLOG("blockcnt does not match value in superblock\n");
18558a6bb6a8SArtur Paszkiewicz 				rc = -EINVAL;
18568a6bb6a8SArtur Paszkiewicz 			}
1857c25b80e2SArtur Paszkiewicz 		}
1858c25b80e2SArtur Paszkiewicz 
18598a6bb6a8SArtur Paszkiewicz 		if (rc != 0) {
18605558f3f5SArtur Paszkiewicz 			raid_bdev->configure_cb = NULL;
18618a6bb6a8SArtur Paszkiewicz 			if (raid_bdev->module->stop != NULL) {
18628a6bb6a8SArtur Paszkiewicz 				raid_bdev->module->stop(raid_bdev);
18638a6bb6a8SArtur Paszkiewicz 			}
18648a6bb6a8SArtur Paszkiewicz 			return rc;
18658a6bb6a8SArtur Paszkiewicz 		}
18668a6bb6a8SArtur Paszkiewicz 
186777b8f7b6SArtur Paszkiewicz 		raid_bdev_write_superblock(raid_bdev, raid_bdev_configure_write_sb_cb, NULL);
186877b8f7b6SArtur Paszkiewicz 	} else {
186977b8f7b6SArtur Paszkiewicz 		raid_bdev_configure_cont(raid_bdev);
18700b4ca522SArtur Paszkiewicz 	}
187107fe6a43SSeth Howell 
187207fe6a43SSeth Howell 	return 0;
187307fe6a43SSeth Howell }
187407fe6a43SSeth Howell 
187507fe6a43SSeth Howell /*
187607fe6a43SSeth Howell  * brief:
187707fe6a43SSeth Howell  * If raid bdev is online and registered, change the bdev state to
187807fe6a43SSeth Howell  * configuring and unregister this raid device. Queue this raid device
187907fe6a43SSeth Howell  * in configuring list
188007fe6a43SSeth Howell  * params:
188107fe6a43SSeth Howell  * raid_bdev - pointer to raid bdev
188207fe6a43SSeth Howell  * cb_fn - callback function
188307fe6a43SSeth Howell  * cb_arg - argument to callback function
188407fe6a43SSeth Howell  * returns:
188507fe6a43SSeth Howell  * none
188607fe6a43SSeth Howell  */
188707fe6a43SSeth Howell static void
188807fe6a43SSeth Howell raid_bdev_deconfigure(struct raid_bdev *raid_bdev, raid_bdev_destruct_cb cb_fn,
188907fe6a43SSeth Howell 		      void *cb_arg)
189007fe6a43SSeth Howell {
189107fe6a43SSeth Howell 	if (raid_bdev->state != RAID_BDEV_STATE_ONLINE) {
189207fe6a43SSeth Howell 		if (cb_fn) {
189307fe6a43SSeth Howell 			cb_fn(cb_arg, 0);
189407fe6a43SSeth Howell 		}
189507fe6a43SSeth Howell 		return;
189607fe6a43SSeth Howell 	}
189707fe6a43SSeth Howell 
189807fe6a43SSeth Howell 	raid_bdev->state = RAID_BDEV_STATE_OFFLINE;
18991960ef16SJosh Soref 	SPDK_DEBUGLOG(bdev_raid, "raid bdev state changing from online to offline\n");
190007fe6a43SSeth Howell 
190107fe6a43SSeth Howell 	spdk_bdev_unregister(&raid_bdev->bdev, cb_fn, cb_arg);
190207fe6a43SSeth Howell }
190307fe6a43SSeth Howell 
190407fe6a43SSeth Howell /*
190507fe6a43SSeth Howell  * brief:
190626861b70SArtur Paszkiewicz  * raid_bdev_find_base_info_by_bdev function finds the base bdev info by bdev.
190707fe6a43SSeth Howell  * params:
190826861b70SArtur Paszkiewicz  * base_bdev - pointer to base bdev
190907fe6a43SSeth Howell  * returns:
191026861b70SArtur Paszkiewicz  * base bdev info if found, otherwise NULL.
191107fe6a43SSeth Howell  */
191226861b70SArtur Paszkiewicz static struct raid_base_bdev_info *
191326861b70SArtur Paszkiewicz raid_bdev_find_base_info_by_bdev(struct spdk_bdev *base_bdev)
191407fe6a43SSeth Howell {
191507fe6a43SSeth Howell 	struct raid_bdev *raid_bdev;
1916a193dcb8SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info;
191707fe6a43SSeth Howell 
191807fe6a43SSeth Howell 	TAILQ_FOREACH(raid_bdev, &g_raid_bdev_list, global_link) {
1919a193dcb8SArtur Paszkiewicz 		RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
19208d1993a5SArtur Paszkiewicz 			if (base_info->desc != NULL &&
19218d1993a5SArtur Paszkiewicz 			    spdk_bdev_desc_get_bdev(base_info->desc) == base_bdev) {
192226861b70SArtur Paszkiewicz 				return base_info;
192307fe6a43SSeth Howell 			}
192407fe6a43SSeth Howell 		}
192507fe6a43SSeth Howell 	}
192607fe6a43SSeth Howell 
192726861b70SArtur Paszkiewicz 	return NULL;
192807fe6a43SSeth Howell }
192907fe6a43SSeth Howell 
1930b42cb0e5SArtur Paszkiewicz static void
19314cc10656SArtur Paszkiewicz raid_bdev_remove_base_bdev_done(struct raid_base_bdev_info *base_info, int status)
19324cc10656SArtur Paszkiewicz {
19332ea7b741SArtur Paszkiewicz 	struct raid_bdev *raid_bdev = base_info->raid_bdev;
19344cc10656SArtur Paszkiewicz 
19352ea7b741SArtur Paszkiewicz 	assert(base_info->remove_scheduled);
19364cc10656SArtur Paszkiewicz 	base_info->remove_scheduled = false;
19372ea7b741SArtur Paszkiewicz 
19382ea7b741SArtur Paszkiewicz 	if (status == 0) {
19392ea7b741SArtur Paszkiewicz 		raid_bdev->num_base_bdevs_operational--;
19402ea7b741SArtur Paszkiewicz 		if (raid_bdev->num_base_bdevs_operational < raid_bdev->min_base_bdevs_operational) {
19412ea7b741SArtur Paszkiewicz 			/* There is not enough base bdevs to keep the raid bdev operational. */
19422ea7b741SArtur Paszkiewicz 			raid_bdev_deconfigure(raid_bdev, base_info->remove_cb, base_info->remove_cb_ctx);
19432ea7b741SArtur Paszkiewicz 			return;
19442ea7b741SArtur Paszkiewicz 		}
19452ea7b741SArtur Paszkiewicz 	}
19462ea7b741SArtur Paszkiewicz 
19474cc10656SArtur Paszkiewicz 	if (base_info->remove_cb != NULL) {
19484cc10656SArtur Paszkiewicz 		base_info->remove_cb(base_info->remove_cb_ctx, status);
19494cc10656SArtur Paszkiewicz 	}
19504cc10656SArtur Paszkiewicz }
19514cc10656SArtur Paszkiewicz 
19524cc10656SArtur Paszkiewicz static void
1953b42cb0e5SArtur Paszkiewicz raid_bdev_remove_base_bdev_on_unquiesced(void *ctx, int status)
1954b42cb0e5SArtur Paszkiewicz {
1955b42cb0e5SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info = ctx;
1956b42cb0e5SArtur Paszkiewicz 	struct raid_bdev *raid_bdev = base_info->raid_bdev;
1957b42cb0e5SArtur Paszkiewicz 
1958b42cb0e5SArtur Paszkiewicz 	if (status != 0) {
1959b42cb0e5SArtur Paszkiewicz 		SPDK_ERRLOG("Failed to unquiesce raid bdev %s: %s\n",
1960b42cb0e5SArtur Paszkiewicz 			    raid_bdev->bdev.name, spdk_strerror(-status));
1961b42cb0e5SArtur Paszkiewicz 	}
1962b42cb0e5SArtur Paszkiewicz 
19634cc10656SArtur Paszkiewicz 	raid_bdev_remove_base_bdev_done(base_info, status);
1964b42cb0e5SArtur Paszkiewicz }
1965b42cb0e5SArtur Paszkiewicz 
1966b42cb0e5SArtur Paszkiewicz static void
1967b42cb0e5SArtur Paszkiewicz raid_bdev_channel_remove_base_bdev(struct spdk_io_channel_iter *i)
1968b42cb0e5SArtur Paszkiewicz {
1969b42cb0e5SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info = spdk_io_channel_iter_get_ctx(i);
1970b42cb0e5SArtur Paszkiewicz 	struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(i);
1971b42cb0e5SArtur Paszkiewicz 	struct raid_bdev_io_channel *raid_ch = spdk_io_channel_get_ctx(ch);
1972fd92e702SArtur Paszkiewicz 	uint8_t idx = raid_bdev_base_bdev_slot(base_info);
1973b42cb0e5SArtur Paszkiewicz 
1974b42cb0e5SArtur Paszkiewicz 	SPDK_DEBUGLOG(bdev_raid, "slot: %u raid_ch: %p\n", idx, raid_ch);
1975b42cb0e5SArtur Paszkiewicz 
1976b42cb0e5SArtur Paszkiewicz 	if (raid_ch->base_channel[idx] != NULL) {
1977b42cb0e5SArtur Paszkiewicz 		spdk_put_io_channel(raid_ch->base_channel[idx]);
1978b42cb0e5SArtur Paszkiewicz 		raid_ch->base_channel[idx] = NULL;
1979b42cb0e5SArtur Paszkiewicz 	}
1980b42cb0e5SArtur Paszkiewicz 
1981aae5e04fSArtur Paszkiewicz 	if (raid_ch->process.ch_processed != NULL) {
1982aae5e04fSArtur Paszkiewicz 		raid_ch->process.ch_processed->base_channel[idx] = NULL;
1983aae5e04fSArtur Paszkiewicz 	}
1984aae5e04fSArtur Paszkiewicz 
1985b42cb0e5SArtur Paszkiewicz 	spdk_for_each_channel_continue(i, 0);
1986b42cb0e5SArtur Paszkiewicz }
1987b42cb0e5SArtur Paszkiewicz 
1988b42cb0e5SArtur Paszkiewicz static void
1989b42cb0e5SArtur Paszkiewicz raid_bdev_channels_remove_base_bdev_done(struct spdk_io_channel_iter *i, int status)
1990b42cb0e5SArtur Paszkiewicz {
1991b42cb0e5SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info = spdk_io_channel_iter_get_ctx(i);
1992b42cb0e5SArtur Paszkiewicz 	struct raid_bdev *raid_bdev = base_info->raid_bdev;
1993b42cb0e5SArtur Paszkiewicz 
19942dc74a00SArtur Paszkiewicz 	raid_bdev_free_base_bdev_resource(base_info);
19952dc74a00SArtur Paszkiewicz 
1996b42cb0e5SArtur Paszkiewicz 	spdk_bdev_unquiesce(&raid_bdev->bdev, &g_raid_if, raid_bdev_remove_base_bdev_on_unquiesced,
1997b42cb0e5SArtur Paszkiewicz 			    base_info);
1998b42cb0e5SArtur Paszkiewicz }
1999b42cb0e5SArtur Paszkiewicz 
2000b42cb0e5SArtur Paszkiewicz static void
2001cb768e81SArtur Paszkiewicz raid_bdev_remove_base_bdev_cont(struct raid_base_bdev_info *base_info)
2002cb768e81SArtur Paszkiewicz {
2003cb768e81SArtur Paszkiewicz 	raid_bdev_deconfigure_base_bdev(base_info);
2004cb768e81SArtur Paszkiewicz 
2005cb768e81SArtur Paszkiewicz 	spdk_for_each_channel(base_info->raid_bdev, raid_bdev_channel_remove_base_bdev, base_info,
2006cb768e81SArtur Paszkiewicz 			      raid_bdev_channels_remove_base_bdev_done);
2007cb768e81SArtur Paszkiewicz }
2008cb768e81SArtur Paszkiewicz 
2009cb768e81SArtur Paszkiewicz static void
2010cb768e81SArtur Paszkiewicz raid_bdev_remove_base_bdev_write_sb_cb(int status, struct raid_bdev *raid_bdev, void *ctx)
2011cb768e81SArtur Paszkiewicz {
2012cb768e81SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info = ctx;
2013cb768e81SArtur Paszkiewicz 
2014cb768e81SArtur Paszkiewicz 	if (status != 0) {
2015cb768e81SArtur Paszkiewicz 		SPDK_ERRLOG("Failed to write raid bdev '%s' superblock: %s\n",
2016cb768e81SArtur Paszkiewicz 			    raid_bdev->bdev.name, spdk_strerror(-status));
2017cb768e81SArtur Paszkiewicz 		raid_bdev_remove_base_bdev_done(base_info, status);
2018cb768e81SArtur Paszkiewicz 		return;
2019cb768e81SArtur Paszkiewicz 	}
2020cb768e81SArtur Paszkiewicz 
2021cb768e81SArtur Paszkiewicz 	raid_bdev_remove_base_bdev_cont(base_info);
2022cb768e81SArtur Paszkiewicz }
2023cb768e81SArtur Paszkiewicz 
2024cb768e81SArtur Paszkiewicz static void
2025b42cb0e5SArtur Paszkiewicz raid_bdev_remove_base_bdev_on_quiesced(void *ctx, int status)
2026b42cb0e5SArtur Paszkiewicz {
2027b42cb0e5SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info = ctx;
2028b42cb0e5SArtur Paszkiewicz 	struct raid_bdev *raid_bdev = base_info->raid_bdev;
2029b42cb0e5SArtur Paszkiewicz 
2030b42cb0e5SArtur Paszkiewicz 	if (status != 0) {
2031b42cb0e5SArtur Paszkiewicz 		SPDK_ERRLOG("Failed to quiesce raid bdev %s: %s\n",
2032b42cb0e5SArtur Paszkiewicz 			    raid_bdev->bdev.name, spdk_strerror(-status));
20334cc10656SArtur Paszkiewicz 		raid_bdev_remove_base_bdev_done(base_info, status);
2034b42cb0e5SArtur Paszkiewicz 		return;
2035b42cb0e5SArtur Paszkiewicz 	}
2036b42cb0e5SArtur Paszkiewicz 
2037cb768e81SArtur Paszkiewicz 	if (raid_bdev->sb) {
2038cb768e81SArtur Paszkiewicz 		struct raid_bdev_superblock *sb = raid_bdev->sb;
2039cb768e81SArtur Paszkiewicz 		uint8_t slot = raid_bdev_base_bdev_slot(base_info);
2040cb768e81SArtur Paszkiewicz 		uint8_t i;
20416518a98dSArtur Paszkiewicz 
2042cb768e81SArtur Paszkiewicz 		for (i = 0; i < sb->base_bdevs_size; i++) {
2043cb768e81SArtur Paszkiewicz 			struct raid_bdev_sb_base_bdev *sb_base_bdev = &sb->base_bdevs[i];
2044cb768e81SArtur Paszkiewicz 
2045cb768e81SArtur Paszkiewicz 			if (sb_base_bdev->state == RAID_SB_BASE_BDEV_CONFIGURED &&
2046cb768e81SArtur Paszkiewicz 			    sb_base_bdev->slot == slot) {
2047f1a03e33SArtur Paszkiewicz 				if (base_info->is_failed) {
2048cb768e81SArtur Paszkiewicz 					sb_base_bdev->state = RAID_SB_BASE_BDEV_FAILED;
2049f1a03e33SArtur Paszkiewicz 				} else {
2050f1a03e33SArtur Paszkiewicz 					sb_base_bdev->state = RAID_SB_BASE_BDEV_MISSING;
2051f1a03e33SArtur Paszkiewicz 				}
2052cb768e81SArtur Paszkiewicz 
2053cb768e81SArtur Paszkiewicz 				raid_bdev_write_superblock(raid_bdev, raid_bdev_remove_base_bdev_write_sb_cb, base_info);
2054cb768e81SArtur Paszkiewicz 				return;
2055cb768e81SArtur Paszkiewicz 			}
2056cb768e81SArtur Paszkiewicz 		}
2057cb768e81SArtur Paszkiewicz 	}
2058cb768e81SArtur Paszkiewicz 
2059cb768e81SArtur Paszkiewicz 	raid_bdev_remove_base_bdev_cont(base_info);
2060b42cb0e5SArtur Paszkiewicz }
2061b42cb0e5SArtur Paszkiewicz 
20620ace905fSArtur Paszkiewicz static int
2063d6fa87aeSArtur Paszkiewicz raid_bdev_remove_base_bdev_quiesce(struct raid_base_bdev_info *base_info)
2064d6fa87aeSArtur Paszkiewicz {
2065d6fa87aeSArtur Paszkiewicz 	assert(spdk_get_thread() == spdk_thread_get_app_thread());
2066d6fa87aeSArtur Paszkiewicz 
2067d6fa87aeSArtur Paszkiewicz 	return spdk_bdev_quiesce(&base_info->raid_bdev->bdev, &g_raid_if,
2068d6fa87aeSArtur Paszkiewicz 				 raid_bdev_remove_base_bdev_on_quiesced, base_info);
2069d6fa87aeSArtur Paszkiewicz }
2070d6fa87aeSArtur Paszkiewicz 
2071d6fa87aeSArtur Paszkiewicz struct raid_bdev_process_base_bdev_remove_ctx {
2072d6fa87aeSArtur Paszkiewicz 	struct raid_bdev_process *process;
2073d6fa87aeSArtur Paszkiewicz 	struct raid_base_bdev_info *base_info;
2074d6fa87aeSArtur Paszkiewicz 	uint8_t num_base_bdevs_operational;
2075d6fa87aeSArtur Paszkiewicz };
2076d6fa87aeSArtur Paszkiewicz 
2077d6fa87aeSArtur Paszkiewicz static void
2078d6fa87aeSArtur Paszkiewicz _raid_bdev_process_base_bdev_remove_cont(void *ctx)
2079d6fa87aeSArtur Paszkiewicz {
2080d6fa87aeSArtur Paszkiewicz 	struct raid_base_bdev_info *base_info = ctx;
2081d6fa87aeSArtur Paszkiewicz 	int ret;
2082d6fa87aeSArtur Paszkiewicz 
2083d6fa87aeSArtur Paszkiewicz 	ret = raid_bdev_remove_base_bdev_quiesce(base_info);
2084d6fa87aeSArtur Paszkiewicz 	if (ret != 0) {
2085d6fa87aeSArtur Paszkiewicz 		raid_bdev_remove_base_bdev_done(base_info, ret);
2086d6fa87aeSArtur Paszkiewicz 	}
2087d6fa87aeSArtur Paszkiewicz }
2088d6fa87aeSArtur Paszkiewicz 
2089d6fa87aeSArtur Paszkiewicz static void
2090d6fa87aeSArtur Paszkiewicz raid_bdev_process_base_bdev_remove_cont(void *_ctx)
2091d6fa87aeSArtur Paszkiewicz {
2092d6fa87aeSArtur Paszkiewicz 	struct raid_bdev_process_base_bdev_remove_ctx *ctx = _ctx;
2093d6fa87aeSArtur Paszkiewicz 	struct raid_base_bdev_info *base_info = ctx->base_info;
2094d6fa87aeSArtur Paszkiewicz 
2095d6fa87aeSArtur Paszkiewicz 	free(ctx);
2096d6fa87aeSArtur Paszkiewicz 
2097d6fa87aeSArtur Paszkiewicz 	spdk_thread_send_msg(spdk_thread_get_app_thread(), _raid_bdev_process_base_bdev_remove_cont,
2098d6fa87aeSArtur Paszkiewicz 			     base_info);
2099d6fa87aeSArtur Paszkiewicz }
2100d6fa87aeSArtur Paszkiewicz 
2101d6fa87aeSArtur Paszkiewicz static void
2102d6fa87aeSArtur Paszkiewicz _raid_bdev_process_base_bdev_remove(void *_ctx)
2103d6fa87aeSArtur Paszkiewicz {
2104d6fa87aeSArtur Paszkiewicz 	struct raid_bdev_process_base_bdev_remove_ctx *ctx = _ctx;
2105d6fa87aeSArtur Paszkiewicz 	struct raid_bdev_process *process = ctx->process;
2106d6fa87aeSArtur Paszkiewicz 	int ret;
2107d6fa87aeSArtur Paszkiewicz 
2108d6fa87aeSArtur Paszkiewicz 	if (ctx->base_info != process->target &&
2109d6fa87aeSArtur Paszkiewicz 	    ctx->num_base_bdevs_operational > process->raid_bdev->min_base_bdevs_operational) {
2110d6fa87aeSArtur Paszkiewicz 		/* process doesn't need to be stopped */
2111d6fa87aeSArtur Paszkiewicz 		raid_bdev_process_base_bdev_remove_cont(ctx);
2112d6fa87aeSArtur Paszkiewicz 		return;
2113d6fa87aeSArtur Paszkiewicz 	}
2114d6fa87aeSArtur Paszkiewicz 
2115d6fa87aeSArtur Paszkiewicz 	assert(process->state > RAID_PROCESS_STATE_INIT &&
2116d6fa87aeSArtur Paszkiewicz 	       process->state < RAID_PROCESS_STATE_STOPPED);
2117d6fa87aeSArtur Paszkiewicz 
2118d6fa87aeSArtur Paszkiewicz 	ret = raid_bdev_process_add_finish_action(process, raid_bdev_process_base_bdev_remove_cont, ctx);
2119d6fa87aeSArtur Paszkiewicz 	if (ret != 0) {
2120d6fa87aeSArtur Paszkiewicz 		raid_bdev_remove_base_bdev_done(ctx->base_info, ret);
2121d6fa87aeSArtur Paszkiewicz 		free(ctx);
2122d6fa87aeSArtur Paszkiewicz 		return;
2123d6fa87aeSArtur Paszkiewicz 	}
2124d6fa87aeSArtur Paszkiewicz 
2125d6fa87aeSArtur Paszkiewicz 	process->state = RAID_PROCESS_STATE_STOPPING;
2126d6fa87aeSArtur Paszkiewicz 
2127d6fa87aeSArtur Paszkiewicz 	if (process->status == 0) {
2128d6fa87aeSArtur Paszkiewicz 		process->status = -ENODEV;
2129d6fa87aeSArtur Paszkiewicz 	}
2130d6fa87aeSArtur Paszkiewicz }
2131d6fa87aeSArtur Paszkiewicz 
2132d6fa87aeSArtur Paszkiewicz static int
2133d6fa87aeSArtur Paszkiewicz raid_bdev_process_base_bdev_remove(struct raid_bdev_process *process,
2134d6fa87aeSArtur Paszkiewicz 				   struct raid_base_bdev_info *base_info)
2135d6fa87aeSArtur Paszkiewicz {
2136d6fa87aeSArtur Paszkiewicz 	struct raid_bdev_process_base_bdev_remove_ctx *ctx;
2137d6fa87aeSArtur Paszkiewicz 
2138d6fa87aeSArtur Paszkiewicz 	assert(spdk_get_thread() == spdk_thread_get_app_thread());
2139d6fa87aeSArtur Paszkiewicz 
2140d6fa87aeSArtur Paszkiewicz 	ctx = calloc(1, sizeof(*ctx));
2141d6fa87aeSArtur Paszkiewicz 	if (ctx == NULL) {
2142d6fa87aeSArtur Paszkiewicz 		return -ENOMEM;
2143d6fa87aeSArtur Paszkiewicz 	}
2144d6fa87aeSArtur Paszkiewicz 
2145d6fa87aeSArtur Paszkiewicz 	/*
2146d6fa87aeSArtur Paszkiewicz 	 * We have to send the process and num_base_bdevs_operational in the message ctx
2147d6fa87aeSArtur Paszkiewicz 	 * because the process thread should not access raid_bdev's properties. Particularly,
2148d6fa87aeSArtur Paszkiewicz 	 * raid_bdev->process may be cleared by the time the message is handled, but ctx->process
2149d6fa87aeSArtur Paszkiewicz 	 * will still be valid until the process is fully stopped.
2150d6fa87aeSArtur Paszkiewicz 	 */
2151d6fa87aeSArtur Paszkiewicz 	ctx->base_info = base_info;
2152d6fa87aeSArtur Paszkiewicz 	ctx->process = process;
21532ea7b741SArtur Paszkiewicz 	/*
21542ea7b741SArtur Paszkiewicz 	 * raid_bdev->num_base_bdevs_operational can't be used here because it is decremented
21552ea7b741SArtur Paszkiewicz 	 * after the removal and more than one base bdev may be removed at the same time
21562ea7b741SArtur Paszkiewicz 	 */
21572ea7b741SArtur Paszkiewicz 	RAID_FOR_EACH_BASE_BDEV(process->raid_bdev, base_info) {
21586518a98dSArtur Paszkiewicz 		if (base_info->is_configured && !base_info->remove_scheduled) {
21592ea7b741SArtur Paszkiewicz 			ctx->num_base_bdevs_operational++;
21602ea7b741SArtur Paszkiewicz 		}
21612ea7b741SArtur Paszkiewicz 	}
2162d6fa87aeSArtur Paszkiewicz 
2163d6fa87aeSArtur Paszkiewicz 	spdk_thread_send_msg(process->thread, _raid_bdev_process_base_bdev_remove, ctx);
2164d6fa87aeSArtur Paszkiewicz 
2165d6fa87aeSArtur Paszkiewicz 	return 0;
2166d6fa87aeSArtur Paszkiewicz }
2167d6fa87aeSArtur Paszkiewicz 
2168d6fa87aeSArtur Paszkiewicz static int
21690ace905fSArtur Paszkiewicz _raid_bdev_remove_base_bdev(struct raid_base_bdev_info *base_info,
2170887b8ec4SArtur Paszkiewicz 			    raid_base_bdev_cb cb_fn, void *cb_ctx)
217107fe6a43SSeth Howell {
21720ace905fSArtur Paszkiewicz 	struct raid_bdev *raid_bdev = base_info->raid_bdev;
2173d6fa87aeSArtur Paszkiewicz 	int ret = 0;
217407fe6a43SSeth Howell 
21750ace905fSArtur Paszkiewicz 	SPDK_DEBUGLOG(bdev_raid, "%s\n", base_info->name);
217607fe6a43SSeth Howell 
21774dd2a0d3SArtur Paszkiewicz 	assert(spdk_get_thread() == spdk_thread_get_app_thread());
21784dd2a0d3SArtur Paszkiewicz 
2179b3750343SArtur Paszkiewicz 	if (base_info->remove_scheduled || !base_info->is_configured) {
2180d6fa87aeSArtur Paszkiewicz 		return -ENODEV;
2181b42cb0e5SArtur Paszkiewicz 	}
2182b42cb0e5SArtur Paszkiewicz 
2183a193dcb8SArtur Paszkiewicz 	assert(base_info->desc);
2184a193dcb8SArtur Paszkiewicz 	base_info->remove_scheduled = true;
218507fe6a43SSeth Howell 
21864ad1ac90SArtur Paszkiewicz 	if (raid_bdev->state != RAID_BDEV_STATE_ONLINE) {
218707fe6a43SSeth Howell 		/*
218807fe6a43SSeth Howell 		 * As raid bdev is not registered yet or already unregistered,
218907fe6a43SSeth Howell 		 * so cleanup should be done here itself.
2190255d0786SArtur Paszkiewicz 		 *
2191255d0786SArtur Paszkiewicz 		 * Removing a base bdev at this stage does not change the number of operational
2192255d0786SArtur Paszkiewicz 		 * base bdevs, only the number of discovered base bdevs.
219307fe6a43SSeth Howell 		 */
219426861b70SArtur Paszkiewicz 		raid_bdev_free_base_bdev_resource(base_info);
2195bf3ddff0SArtur Paszkiewicz 		base_info->remove_scheduled = false;
2196bad11eeaSArtur Paszkiewicz 		if (raid_bdev->num_base_bdevs_discovered == 0 &&
2197bad11eeaSArtur Paszkiewicz 		    raid_bdev->state == RAID_BDEV_STATE_OFFLINE) {
219807fe6a43SSeth Howell 			/* There is no base bdev for this raid, so free the raid device. */
219995a04949SArtur Paszkiewicz 			raid_bdev_cleanup_and_free(raid_bdev);
2200b42cb0e5SArtur Paszkiewicz 		}
22019d6e1f5bSYankun Li 		if (cb_fn != NULL) {
22029d6e1f5bSYankun Li 			cb_fn(cb_ctx, 0);
22039d6e1f5bSYankun Li 		}
22042ea7b741SArtur Paszkiewicz 	} else if (raid_bdev->min_base_bdevs_operational == raid_bdev->num_base_bdevs) {
22052ea7b741SArtur Paszkiewicz 		/* This raid bdev does not tolerate removing a base bdev. */
22062ea7b741SArtur Paszkiewicz 		raid_bdev->num_base_bdevs_operational--;
220723850b03SKrzysztof Smolinski 		raid_bdev_deconfigure(raid_bdev, cb_fn, cb_ctx);
22082ea7b741SArtur Paszkiewicz 	} else {
22092ea7b741SArtur Paszkiewicz 		base_info->remove_cb = cb_fn;
22102ea7b741SArtur Paszkiewicz 		base_info->remove_cb_ctx = cb_ctx;
22112ea7b741SArtur Paszkiewicz 
22122ea7b741SArtur Paszkiewicz 		if (raid_bdev->process != NULL) {
2213d6fa87aeSArtur Paszkiewicz 			ret = raid_bdev_process_base_bdev_remove(raid_bdev->process, base_info);
2214b42cb0e5SArtur Paszkiewicz 		} else {
2215d6fa87aeSArtur Paszkiewicz 			ret = raid_bdev_remove_base_bdev_quiesce(base_info);
2216d6fa87aeSArtur Paszkiewicz 		}
2217b42cb0e5SArtur Paszkiewicz 
2218b42cb0e5SArtur Paszkiewicz 		if (ret != 0) {
2219b42cb0e5SArtur Paszkiewicz 			base_info->remove_scheduled = false;
222007fe6a43SSeth Howell 		}
22212ea7b741SArtur Paszkiewicz 	}
22222ea7b741SArtur Paszkiewicz 
2223d6fa87aeSArtur Paszkiewicz 	return ret;
222407fe6a43SSeth Howell }
222507fe6a43SSeth Howell 
222607fe6a43SSeth Howell /*
222707fe6a43SSeth Howell  * brief:
22280ace905fSArtur Paszkiewicz  * raid_bdev_remove_base_bdev function is called by below layers when base_bdev
22290ace905fSArtur Paszkiewicz  * is removed. This function checks if this base bdev is part of any raid bdev
22300ace905fSArtur Paszkiewicz  * or not. If yes, it takes necessary action on that particular raid bdev.
22310ace905fSArtur Paszkiewicz  * params:
22320ace905fSArtur Paszkiewicz  * base_bdev - pointer to base bdev which got removed
22330ace905fSArtur Paszkiewicz  * cb_fn - callback function
22340ace905fSArtur Paszkiewicz  * cb_arg - argument to callback function
22350ace905fSArtur Paszkiewicz  * returns:
22360ace905fSArtur Paszkiewicz  * 0 - success
22370ace905fSArtur Paszkiewicz  * non zero - failure
22380ace905fSArtur Paszkiewicz  */
22390ace905fSArtur Paszkiewicz int
2240887b8ec4SArtur Paszkiewicz raid_bdev_remove_base_bdev(struct spdk_bdev *base_bdev, raid_base_bdev_cb cb_fn, void *cb_ctx)
22410ace905fSArtur Paszkiewicz {
22420ace905fSArtur Paszkiewicz 	struct raid_base_bdev_info *base_info;
22430ace905fSArtur Paszkiewicz 
22440ace905fSArtur Paszkiewicz 	/* Find the raid_bdev which has claimed this base_bdev */
22450ace905fSArtur Paszkiewicz 	base_info = raid_bdev_find_base_info_by_bdev(base_bdev);
22460ace905fSArtur Paszkiewicz 	if (!base_info) {
22470ace905fSArtur Paszkiewicz 		SPDK_ERRLOG("bdev to remove '%s' not found\n", base_bdev->name);
22480ace905fSArtur Paszkiewicz 		return -ENODEV;
22490ace905fSArtur Paszkiewicz 	}
22500ace905fSArtur Paszkiewicz 
22510ace905fSArtur Paszkiewicz 	return _raid_bdev_remove_base_bdev(base_info, cb_fn, cb_ctx);
22520ace905fSArtur Paszkiewicz }
22530ace905fSArtur Paszkiewicz 
2254ceb2ad0cSArtur Paszkiewicz static void
2255f1a03e33SArtur Paszkiewicz raid_bdev_fail_base_remove_cb(void *ctx, int status)
2256f1a03e33SArtur Paszkiewicz {
2257f1a03e33SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info = ctx;
2258f1a03e33SArtur Paszkiewicz 
2259f1a03e33SArtur Paszkiewicz 	if (status != 0) {
2260f1a03e33SArtur Paszkiewicz 		SPDK_WARNLOG("Failed to remove base bdev %s\n", base_info->name);
2261f1a03e33SArtur Paszkiewicz 		base_info->is_failed = false;
2262f1a03e33SArtur Paszkiewicz 	}
2263f1a03e33SArtur Paszkiewicz }
2264f1a03e33SArtur Paszkiewicz 
2265f1a03e33SArtur Paszkiewicz static void
2266f1a03e33SArtur Paszkiewicz _raid_bdev_fail_base_bdev(void *ctx)
2267f1a03e33SArtur Paszkiewicz {
2268f1a03e33SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info = ctx;
2269f1a03e33SArtur Paszkiewicz 	int rc;
2270f1a03e33SArtur Paszkiewicz 
2271f1a03e33SArtur Paszkiewicz 	if (base_info->is_failed) {
2272f1a03e33SArtur Paszkiewicz 		return;
2273f1a03e33SArtur Paszkiewicz 	}
2274f1a03e33SArtur Paszkiewicz 	base_info->is_failed = true;
2275f1a03e33SArtur Paszkiewicz 
2276f1a03e33SArtur Paszkiewicz 	SPDK_NOTICELOG("Failing base bdev in slot %d ('%s') of raid bdev '%s'\n",
2277f1a03e33SArtur Paszkiewicz 		       raid_bdev_base_bdev_slot(base_info), base_info->name, base_info->raid_bdev->bdev.name);
2278f1a03e33SArtur Paszkiewicz 
2279f1a03e33SArtur Paszkiewicz 	rc = _raid_bdev_remove_base_bdev(base_info, raid_bdev_fail_base_remove_cb, base_info);
2280f1a03e33SArtur Paszkiewicz 	if (rc != 0) {
2281f1a03e33SArtur Paszkiewicz 		raid_bdev_fail_base_remove_cb(base_info, rc);
2282f1a03e33SArtur Paszkiewicz 	}
2283f1a03e33SArtur Paszkiewicz }
2284f1a03e33SArtur Paszkiewicz 
2285f1a03e33SArtur Paszkiewicz void
2286f1a03e33SArtur Paszkiewicz raid_bdev_fail_base_bdev(struct raid_base_bdev_info *base_info)
2287f1a03e33SArtur Paszkiewicz {
2288f1a03e33SArtur Paszkiewicz 	spdk_thread_exec_msg(spdk_thread_get_app_thread(), _raid_bdev_fail_base_bdev, base_info);
2289f1a03e33SArtur Paszkiewicz }
2290f1a03e33SArtur Paszkiewicz 
2291f1a03e33SArtur Paszkiewicz static void
2292ceb2ad0cSArtur Paszkiewicz raid_bdev_resize_write_sb_cb(int status, struct raid_bdev *raid_bdev, void *ctx)
2293ceb2ad0cSArtur Paszkiewicz {
2294ceb2ad0cSArtur Paszkiewicz 	if (status != 0) {
2295ceb2ad0cSArtur Paszkiewicz 		SPDK_ERRLOG("Failed to write raid bdev '%s' superblock after resizing the bdev: %s\n",
2296ceb2ad0cSArtur Paszkiewicz 			    raid_bdev->bdev.name, spdk_strerror(-status));
2297ceb2ad0cSArtur Paszkiewicz 	}
2298ceb2ad0cSArtur Paszkiewicz }
2299ceb2ad0cSArtur Paszkiewicz 
23000ace905fSArtur Paszkiewicz /*
23010ace905fSArtur Paszkiewicz  * brief:
2302c9224e26SShuhei Matsumoto  * raid_bdev_resize_base_bdev function is called by below layers when base_bdev
2303c9224e26SShuhei Matsumoto  * is resized. This function checks if the smallest size of the base_bdevs is changed.
2304c9224e26SShuhei Matsumoto  * If yes, call module handler to resize the raid_bdev if implemented.
2305c9224e26SShuhei Matsumoto  * params:
2306c9224e26SShuhei Matsumoto  * base_bdev - pointer to base bdev which got resized.
2307c9224e26SShuhei Matsumoto  * returns:
2308c9224e26SShuhei Matsumoto  * none
2309c9224e26SShuhei Matsumoto  */
2310c9224e26SShuhei Matsumoto static void
2311c9224e26SShuhei Matsumoto raid_bdev_resize_base_bdev(struct spdk_bdev *base_bdev)
2312c9224e26SShuhei Matsumoto {
231326861b70SArtur Paszkiewicz 	struct raid_bdev *raid_bdev;
2314c9224e26SShuhei Matsumoto 	struct raid_base_bdev_info *base_info;
2315ba09b57fSArtur Paszkiewicz 	uint64_t blockcnt_old;
2316c9224e26SShuhei Matsumoto 
2317c9224e26SShuhei Matsumoto 	SPDK_DEBUGLOG(bdev_raid, "raid_bdev_resize_base_bdev\n");
2318c9224e26SShuhei Matsumoto 
231926861b70SArtur Paszkiewicz 	base_info = raid_bdev_find_base_info_by_bdev(base_bdev);
232026861b70SArtur Paszkiewicz 
2321c9224e26SShuhei Matsumoto 	/* Find the raid_bdev which has claimed this base_bdev */
232226861b70SArtur Paszkiewicz 	if (!base_info) {
2323c9224e26SShuhei Matsumoto 		SPDK_ERRLOG("raid_bdev whose base_bdev '%s' not found\n", base_bdev->name);
2324c9224e26SShuhei Matsumoto 		return;
2325c9224e26SShuhei Matsumoto 	}
232626861b70SArtur Paszkiewicz 	raid_bdev = base_info->raid_bdev;
2327c9224e26SShuhei Matsumoto 
2328c9224e26SShuhei Matsumoto 	assert(spdk_get_thread() == spdk_thread_get_app_thread());
2329c9224e26SShuhei Matsumoto 
2330c9224e26SShuhei Matsumoto 	SPDK_NOTICELOG("base_bdev '%s' was resized: old size %" PRIu64 ", new size %" PRIu64 "\n",
2331c9224e26SShuhei Matsumoto 		       base_bdev->name, base_info->blockcnt, base_bdev->blockcnt);
2332c9224e26SShuhei Matsumoto 
23332e6e9553SArtur Paszkiewicz 	base_info->blockcnt = base_bdev->blockcnt;
23342e6e9553SArtur Paszkiewicz 
2335ceb2ad0cSArtur Paszkiewicz 	if (!raid_bdev->module->resize) {
2336ceb2ad0cSArtur Paszkiewicz 		return;
2337ceb2ad0cSArtur Paszkiewicz 	}
2338ceb2ad0cSArtur Paszkiewicz 
2339ba09b57fSArtur Paszkiewicz 	blockcnt_old = raid_bdev->bdev.blockcnt;
2340ceb2ad0cSArtur Paszkiewicz 	if (raid_bdev->module->resize(raid_bdev) == false) {
2341ceb2ad0cSArtur Paszkiewicz 		return;
2342ceb2ad0cSArtur Paszkiewicz 	}
2343ceb2ad0cSArtur Paszkiewicz 
2344ba09b57fSArtur Paszkiewicz 	SPDK_NOTICELOG("raid bdev '%s': block count was changed from %" PRIu64 " to %" PRIu64 "\n",
2345ba09b57fSArtur Paszkiewicz 		       raid_bdev->bdev.name, blockcnt_old, raid_bdev->bdev.blockcnt);
2346ba09b57fSArtur Paszkiewicz 
2347ceb2ad0cSArtur Paszkiewicz 	if (raid_bdev->superblock_enabled) {
2348ceb2ad0cSArtur Paszkiewicz 		struct raid_bdev_superblock *sb = raid_bdev->sb;
2349ceb2ad0cSArtur Paszkiewicz 		uint8_t i;
2350ceb2ad0cSArtur Paszkiewicz 
2351ceb2ad0cSArtur Paszkiewicz 		for (i = 0; i < sb->base_bdevs_size; i++) {
2352ceb2ad0cSArtur Paszkiewicz 			struct raid_bdev_sb_base_bdev *sb_base_bdev = &sb->base_bdevs[i];
2353ceb2ad0cSArtur Paszkiewicz 
2354d005e023SArtur Paszkiewicz 			if (sb_base_bdev->slot < raid_bdev->num_base_bdevs) {
2355ceb2ad0cSArtur Paszkiewicz 				base_info = &raid_bdev->base_bdev_info[sb_base_bdev->slot];
2356ceb2ad0cSArtur Paszkiewicz 				sb_base_bdev->data_size = base_info->data_size;
2357ceb2ad0cSArtur Paszkiewicz 			}
2358ceb2ad0cSArtur Paszkiewicz 		}
2359ceb2ad0cSArtur Paszkiewicz 		sb->raid_size = raid_bdev->bdev.blockcnt;
2360ceb2ad0cSArtur Paszkiewicz 		raid_bdev_write_superblock(raid_bdev, raid_bdev_resize_write_sb_cb, NULL);
2361c9224e26SShuhei Matsumoto 	}
2362c9224e26SShuhei Matsumoto }
2363c9224e26SShuhei Matsumoto 
2364c9224e26SShuhei Matsumoto /*
2365c9224e26SShuhei Matsumoto  * brief:
2366d8a18924SShuhei Matsumoto  * raid_bdev_event_base_bdev function is called by below layers when base_bdev
2367d8a18924SShuhei Matsumoto  * triggers asynchronous event.
2368d8a18924SShuhei Matsumoto  * params:
2369d8a18924SShuhei Matsumoto  * type - event details.
2370d8a18924SShuhei Matsumoto  * bdev - bdev that triggered event.
2371d8a18924SShuhei Matsumoto  * event_ctx - context for event.
2372d8a18924SShuhei Matsumoto  * returns:
2373d8a18924SShuhei Matsumoto  * none
2374d8a18924SShuhei Matsumoto  */
2375d8a18924SShuhei Matsumoto static void
2376d8a18924SShuhei Matsumoto raid_bdev_event_base_bdev(enum spdk_bdev_event_type type, struct spdk_bdev *bdev,
2377d8a18924SShuhei Matsumoto 			  void *event_ctx)
2378d8a18924SShuhei Matsumoto {
2379b42cb0e5SArtur Paszkiewicz 	int rc;
2380b42cb0e5SArtur Paszkiewicz 
2381d8a18924SShuhei Matsumoto 	switch (type) {
2382d8a18924SShuhei Matsumoto 	case SPDK_BDEV_EVENT_REMOVE:
238323850b03SKrzysztof Smolinski 		rc = raid_bdev_remove_base_bdev(bdev, NULL, NULL);
2384b42cb0e5SArtur Paszkiewicz 		if (rc != 0) {
2385b42cb0e5SArtur Paszkiewicz 			SPDK_ERRLOG("Failed to remove base bdev %s: %s\n",
2386b42cb0e5SArtur Paszkiewicz 				    spdk_bdev_get_name(bdev), spdk_strerror(-rc));
2387b42cb0e5SArtur Paszkiewicz 		}
2388d8a18924SShuhei Matsumoto 		break;
2389c9224e26SShuhei Matsumoto 	case SPDK_BDEV_EVENT_RESIZE:
2390c9224e26SShuhei Matsumoto 		raid_bdev_resize_base_bdev(bdev);
2391c9224e26SShuhei Matsumoto 		break;
2392d8a18924SShuhei Matsumoto 	default:
2393d8a18924SShuhei Matsumoto 		SPDK_NOTICELOG("Unsupported bdev event: type %d\n", type);
2394d8a18924SShuhei Matsumoto 		break;
2395d8a18924SShuhei Matsumoto 	}
2396d8a18924SShuhei Matsumoto }
2397d8a18924SShuhei Matsumoto 
2398d8a18924SShuhei Matsumoto /*
2399d8a18924SShuhei Matsumoto  * brief:
2400dccdd1e5SArtur Paszkiewicz  * Deletes the specified raid bdev
240107fe6a43SSeth Howell  * params:
2402dccdd1e5SArtur Paszkiewicz  * raid_bdev - pointer to raid bdev
240307fe6a43SSeth Howell  * cb_fn - callback function
2404dccdd1e5SArtur Paszkiewicz  * cb_arg - argument to callback function
240507fe6a43SSeth Howell  */
240607fe6a43SSeth Howell void
2407dccdd1e5SArtur Paszkiewicz raid_bdev_delete(struct raid_bdev *raid_bdev, raid_bdev_destruct_cb cb_fn, void *cb_arg)
240807fe6a43SSeth Howell {
2409a193dcb8SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info;
241007fe6a43SSeth Howell 
2411dccdd1e5SArtur Paszkiewicz 	SPDK_DEBUGLOG(bdev_raid, "delete raid bdev: %s\n", raid_bdev->bdev.name);
241207fe6a43SSeth Howell 
241307fe6a43SSeth Howell 	if (raid_bdev->destroy_started) {
24142172c432STomasz Zawadzki 		SPDK_DEBUGLOG(bdev_raid, "destroying raid bdev %s is already started\n",
2415dccdd1e5SArtur Paszkiewicz 			      raid_bdev->bdev.name);
241607fe6a43SSeth Howell 		if (cb_fn) {
241707fe6a43SSeth Howell 			cb_fn(cb_arg, -EALREADY);
241807fe6a43SSeth Howell 		}
241907fe6a43SSeth Howell 		return;
242007fe6a43SSeth Howell 	}
242107fe6a43SSeth Howell 
242207fe6a43SSeth Howell 	raid_bdev->destroy_started = true;
242307fe6a43SSeth Howell 
2424a193dcb8SArtur Paszkiewicz 	RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
2425a193dcb8SArtur Paszkiewicz 		base_info->remove_scheduled = true;
242607fe6a43SSeth Howell 
24274ad1ac90SArtur Paszkiewicz 		if (raid_bdev->state != RAID_BDEV_STATE_ONLINE) {
242807fe6a43SSeth Howell 			/*
242907fe6a43SSeth Howell 			 * As raid bdev is not registered yet or already unregistered,
243007fe6a43SSeth Howell 			 * so cleanup should be done here itself.
243107fe6a43SSeth Howell 			 */
243226861b70SArtur Paszkiewicz 			raid_bdev_free_base_bdev_resource(base_info);
2433df1e07e9SGangCao 		}
2434df1e07e9SGangCao 	}
2435df1e07e9SGangCao 
243607fe6a43SSeth Howell 	if (raid_bdev->num_base_bdevs_discovered == 0) {
243707fe6a43SSeth Howell 		/* There is no base bdev for this raid, so free the raid device. */
243895a04949SArtur Paszkiewicz 		raid_bdev_cleanup_and_free(raid_bdev);
243907fe6a43SSeth Howell 		if (cb_fn) {
244007fe6a43SSeth Howell 			cb_fn(cb_arg, 0);
244107fe6a43SSeth Howell 		}
2442df1e07e9SGangCao 	} else {
244307fe6a43SSeth Howell 		raid_bdev_deconfigure(raid_bdev, cb_fn, cb_arg);
244407fe6a43SSeth Howell 	}
2445df1e07e9SGangCao }
244607fe6a43SSeth Howell 
24479222ff97SArtur Paszkiewicz static void
244850d58ff3SArtur Paszkiewicz raid_bdev_process_finish_write_sb_cb(int status, struct raid_bdev *raid_bdev, void *ctx)
244950d58ff3SArtur Paszkiewicz {
245050d58ff3SArtur Paszkiewicz 	if (status != 0) {
245150d58ff3SArtur Paszkiewicz 		SPDK_ERRLOG("Failed to write raid bdev '%s' superblock after background process finished: %s\n",
245250d58ff3SArtur Paszkiewicz 			    raid_bdev->bdev.name, spdk_strerror(-status));
245350d58ff3SArtur Paszkiewicz 	}
245450d58ff3SArtur Paszkiewicz }
245550d58ff3SArtur Paszkiewicz 
245650d58ff3SArtur Paszkiewicz static void
245750d58ff3SArtur Paszkiewicz raid_bdev_process_finish_write_sb(void *ctx)
245850d58ff3SArtur Paszkiewicz {
245950d58ff3SArtur Paszkiewicz 	struct raid_bdev *raid_bdev = ctx;
246050d58ff3SArtur Paszkiewicz 	struct raid_bdev_superblock *sb = raid_bdev->sb;
246150d58ff3SArtur Paszkiewicz 	struct raid_bdev_sb_base_bdev *sb_base_bdev;
246250d58ff3SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info;
246350d58ff3SArtur Paszkiewicz 	uint8_t i;
246450d58ff3SArtur Paszkiewicz 
246550d58ff3SArtur Paszkiewicz 	for (i = 0; i < sb->base_bdevs_size; i++) {
246650d58ff3SArtur Paszkiewicz 		sb_base_bdev = &sb->base_bdevs[i];
246750d58ff3SArtur Paszkiewicz 
246850d58ff3SArtur Paszkiewicz 		if (sb_base_bdev->state != RAID_SB_BASE_BDEV_CONFIGURED &&
246950d58ff3SArtur Paszkiewicz 		    sb_base_bdev->slot < raid_bdev->num_base_bdevs) {
247050d58ff3SArtur Paszkiewicz 			base_info = &raid_bdev->base_bdev_info[sb_base_bdev->slot];
247150d58ff3SArtur Paszkiewicz 			if (base_info->is_configured) {
247250d58ff3SArtur Paszkiewicz 				sb_base_bdev->state = RAID_SB_BASE_BDEV_CONFIGURED;
24733cd7b237SSebastian Brzezinka 				sb_base_bdev->data_offset = base_info->data_offset;
247450d58ff3SArtur Paszkiewicz 				spdk_uuid_copy(&sb_base_bdev->uuid, &base_info->uuid);
247550d58ff3SArtur Paszkiewicz 			}
247650d58ff3SArtur Paszkiewicz 		}
247750d58ff3SArtur Paszkiewicz 	}
247850d58ff3SArtur Paszkiewicz 
247950d58ff3SArtur Paszkiewicz 	raid_bdev_write_superblock(raid_bdev, raid_bdev_process_finish_write_sb_cb, NULL);
248050d58ff3SArtur Paszkiewicz }
248150d58ff3SArtur Paszkiewicz 
248250d58ff3SArtur Paszkiewicz static void raid_bdev_process_free(struct raid_bdev_process *process);
248350d58ff3SArtur Paszkiewicz 
248450d58ff3SArtur Paszkiewicz static void
248550d58ff3SArtur Paszkiewicz _raid_bdev_process_finish_done(void *ctx)
248650d58ff3SArtur Paszkiewicz {
248750d58ff3SArtur Paszkiewicz 	struct raid_bdev_process *process = ctx;
24889d2b7b41SArtur Paszkiewicz 	struct raid_process_finish_action *finish_action;
24899d2b7b41SArtur Paszkiewicz 
24909d2b7b41SArtur Paszkiewicz 	while ((finish_action = TAILQ_FIRST(&process->finish_actions)) != NULL) {
24919d2b7b41SArtur Paszkiewicz 		TAILQ_REMOVE(&process->finish_actions, finish_action, link);
24929d2b7b41SArtur Paszkiewicz 		finish_action->cb(finish_action->cb_ctx);
24939d2b7b41SArtur Paszkiewicz 		free(finish_action);
24949d2b7b41SArtur Paszkiewicz 	}
249550d58ff3SArtur Paszkiewicz 
249689fd1730Sxupeng9 	spdk_poller_unregister(&process->qos.process_continue_poller);
249789fd1730Sxupeng9 
249850d58ff3SArtur Paszkiewicz 	raid_bdev_process_free(process);
249950d58ff3SArtur Paszkiewicz 
250050d58ff3SArtur Paszkiewicz 	spdk_thread_exit(spdk_get_thread());
250150d58ff3SArtur Paszkiewicz }
250250d58ff3SArtur Paszkiewicz 
250350d58ff3SArtur Paszkiewicz static void
250450d58ff3SArtur Paszkiewicz raid_bdev_process_finish_target_removed(void *ctx, int status)
250550d58ff3SArtur Paszkiewicz {
250650d58ff3SArtur Paszkiewicz 	struct raid_bdev_process *process = ctx;
250750d58ff3SArtur Paszkiewicz 
250850d58ff3SArtur Paszkiewicz 	if (status != 0) {
250950d58ff3SArtur Paszkiewicz 		SPDK_ERRLOG("Failed to remove target bdev: %s\n", spdk_strerror(-status));
251050d58ff3SArtur Paszkiewicz 	}
251150d58ff3SArtur Paszkiewicz 
251250d58ff3SArtur Paszkiewicz 	spdk_thread_send_msg(process->thread, _raid_bdev_process_finish_done, process);
251350d58ff3SArtur Paszkiewicz }
251450d58ff3SArtur Paszkiewicz 
251550d58ff3SArtur Paszkiewicz static void
251650d58ff3SArtur Paszkiewicz raid_bdev_process_finish_unquiesced(void *ctx, int status)
251750d58ff3SArtur Paszkiewicz {
251850d58ff3SArtur Paszkiewicz 	struct raid_bdev_process *process = ctx;
251950d58ff3SArtur Paszkiewicz 
252050d58ff3SArtur Paszkiewicz 	if (status != 0) {
252150d58ff3SArtur Paszkiewicz 		SPDK_ERRLOG("Failed to unquiesce bdev: %s\n", spdk_strerror(-status));
252250d58ff3SArtur Paszkiewicz 	}
252350d58ff3SArtur Paszkiewicz 
252450d58ff3SArtur Paszkiewicz 	if (process->status != 0) {
2525b3750343SArtur Paszkiewicz 		status = _raid_bdev_remove_base_bdev(process->target, raid_bdev_process_finish_target_removed,
2526b3750343SArtur Paszkiewicz 						     process);
2527b3750343SArtur Paszkiewicz 		if (status != 0) {
2528b3750343SArtur Paszkiewicz 			raid_bdev_process_finish_target_removed(process, status);
252950d58ff3SArtur Paszkiewicz 		}
2530b3750343SArtur Paszkiewicz 		return;
253150d58ff3SArtur Paszkiewicz 	}
253250d58ff3SArtur Paszkiewicz 
253350d58ff3SArtur Paszkiewicz 	spdk_thread_send_msg(process->thread, _raid_bdev_process_finish_done, process);
253450d58ff3SArtur Paszkiewicz }
253550d58ff3SArtur Paszkiewicz 
253650d58ff3SArtur Paszkiewicz static void
253750d58ff3SArtur Paszkiewicz raid_bdev_process_finish_unquiesce(void *ctx)
253850d58ff3SArtur Paszkiewicz {
253950d58ff3SArtur Paszkiewicz 	struct raid_bdev_process *process = ctx;
254050d58ff3SArtur Paszkiewicz 	int rc;
254150d58ff3SArtur Paszkiewicz 
254250d58ff3SArtur Paszkiewicz 	rc = spdk_bdev_unquiesce(&process->raid_bdev->bdev, &g_raid_if,
254350d58ff3SArtur Paszkiewicz 				 raid_bdev_process_finish_unquiesced, process);
254450d58ff3SArtur Paszkiewicz 	if (rc != 0) {
254550d58ff3SArtur Paszkiewicz 		raid_bdev_process_finish_unquiesced(process, rc);
254650d58ff3SArtur Paszkiewicz 	}
254750d58ff3SArtur Paszkiewicz }
254850d58ff3SArtur Paszkiewicz 
254950d58ff3SArtur Paszkiewicz static void
255050d58ff3SArtur Paszkiewicz raid_bdev_process_finish_done(void *ctx)
255150d58ff3SArtur Paszkiewicz {
255250d58ff3SArtur Paszkiewicz 	struct raid_bdev_process *process = ctx;
255350d58ff3SArtur Paszkiewicz 	struct raid_bdev *raid_bdev = process->raid_bdev;
255450d58ff3SArtur Paszkiewicz 
255550d58ff3SArtur Paszkiewicz 	if (process->raid_ch != NULL) {
255650d58ff3SArtur Paszkiewicz 		spdk_put_io_channel(spdk_io_channel_from_ctx(process->raid_ch));
255750d58ff3SArtur Paszkiewicz 	}
255850d58ff3SArtur Paszkiewicz 
255950d58ff3SArtur Paszkiewicz 	process->state = RAID_PROCESS_STATE_STOPPED;
256050d58ff3SArtur Paszkiewicz 
256150d58ff3SArtur Paszkiewicz 	if (process->status == 0) {
256250d58ff3SArtur Paszkiewicz 		SPDK_NOTICELOG("Finished %s on raid bdev %s\n",
256350d58ff3SArtur Paszkiewicz 			       raid_bdev_process_to_str(process->type),
256450d58ff3SArtur Paszkiewicz 			       raid_bdev->bdev.name);
25653bb8256aSArtur Paszkiewicz 		if (raid_bdev->superblock_enabled) {
256650d58ff3SArtur Paszkiewicz 			spdk_thread_send_msg(spdk_thread_get_app_thread(),
256750d58ff3SArtur Paszkiewicz 					     raid_bdev_process_finish_write_sb,
256850d58ff3SArtur Paszkiewicz 					     raid_bdev);
256950d58ff3SArtur Paszkiewicz 		}
257050d58ff3SArtur Paszkiewicz 	} else {
257150d58ff3SArtur Paszkiewicz 		SPDK_WARNLOG("Finished %s on raid bdev %s: %s\n",
257250d58ff3SArtur Paszkiewicz 			     raid_bdev_process_to_str(process->type),
257350d58ff3SArtur Paszkiewicz 			     raid_bdev->bdev.name,
257450d58ff3SArtur Paszkiewicz 			     spdk_strerror(-process->status));
257550d58ff3SArtur Paszkiewicz 	}
257650d58ff3SArtur Paszkiewicz 
257750d58ff3SArtur Paszkiewicz 	spdk_thread_send_msg(spdk_thread_get_app_thread(), raid_bdev_process_finish_unquiesce,
257850d58ff3SArtur Paszkiewicz 			     process);
257950d58ff3SArtur Paszkiewicz }
258050d58ff3SArtur Paszkiewicz 
258150d58ff3SArtur Paszkiewicz static void
258250d58ff3SArtur Paszkiewicz __raid_bdev_process_finish(struct spdk_io_channel_iter *i, int status)
258350d58ff3SArtur Paszkiewicz {
258450d58ff3SArtur Paszkiewicz 	struct raid_bdev_process *process = spdk_io_channel_iter_get_ctx(i);
258550d58ff3SArtur Paszkiewicz 
258650d58ff3SArtur Paszkiewicz 	spdk_thread_send_msg(process->thread, raid_bdev_process_finish_done, process);
258750d58ff3SArtur Paszkiewicz }
258850d58ff3SArtur Paszkiewicz 
258950d58ff3SArtur Paszkiewicz static void
259050d58ff3SArtur Paszkiewicz raid_bdev_channel_process_finish(struct spdk_io_channel_iter *i)
259150d58ff3SArtur Paszkiewicz {
259250d58ff3SArtur Paszkiewicz 	struct raid_bdev_process *process = spdk_io_channel_iter_get_ctx(i);
259350d58ff3SArtur Paszkiewicz 	struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(i);
259450d58ff3SArtur Paszkiewicz 	struct raid_bdev_io_channel *raid_ch = spdk_io_channel_get_ctx(ch);
259550d58ff3SArtur Paszkiewicz 
259650d58ff3SArtur Paszkiewicz 	if (process->status == 0) {
259750d58ff3SArtur Paszkiewicz 		uint8_t slot = raid_bdev_base_bdev_slot(process->target);
259850d58ff3SArtur Paszkiewicz 
259950d58ff3SArtur Paszkiewicz 		raid_ch->base_channel[slot] = raid_ch->process.target_ch;
260050d58ff3SArtur Paszkiewicz 		raid_ch->process.target_ch = NULL;
260150d58ff3SArtur Paszkiewicz 	}
260250d58ff3SArtur Paszkiewicz 
260350d58ff3SArtur Paszkiewicz 	raid_bdev_ch_process_cleanup(raid_ch);
260450d58ff3SArtur Paszkiewicz 
260550d58ff3SArtur Paszkiewicz 	spdk_for_each_channel_continue(i, 0);
260650d58ff3SArtur Paszkiewicz }
260750d58ff3SArtur Paszkiewicz 
260850d58ff3SArtur Paszkiewicz static void
260950d58ff3SArtur Paszkiewicz raid_bdev_process_finish_quiesced(void *ctx, int status)
261050d58ff3SArtur Paszkiewicz {
261150d58ff3SArtur Paszkiewicz 	struct raid_bdev_process *process = ctx;
261250d58ff3SArtur Paszkiewicz 	struct raid_bdev *raid_bdev = process->raid_bdev;
261350d58ff3SArtur Paszkiewicz 
261450d58ff3SArtur Paszkiewicz 	if (status != 0) {
261550d58ff3SArtur Paszkiewicz 		SPDK_ERRLOG("Failed to quiesce bdev: %s\n", spdk_strerror(-status));
261650d58ff3SArtur Paszkiewicz 		return;
261750d58ff3SArtur Paszkiewicz 	}
261850d58ff3SArtur Paszkiewicz 
261950d58ff3SArtur Paszkiewicz 	raid_bdev->process = NULL;
2620a6708553SArtur Paszkiewicz 	process->target->is_process_target = false;
2621a6708553SArtur Paszkiewicz 
262250d58ff3SArtur Paszkiewicz 	spdk_for_each_channel(process->raid_bdev, raid_bdev_channel_process_finish, process,
262350d58ff3SArtur Paszkiewicz 			      __raid_bdev_process_finish);
262450d58ff3SArtur Paszkiewicz }
262550d58ff3SArtur Paszkiewicz 
262650d58ff3SArtur Paszkiewicz static void
262750d58ff3SArtur Paszkiewicz _raid_bdev_process_finish(void *ctx)
262850d58ff3SArtur Paszkiewicz {
262950d58ff3SArtur Paszkiewicz 	struct raid_bdev_process *process = ctx;
263050d58ff3SArtur Paszkiewicz 	int rc;
263150d58ff3SArtur Paszkiewicz 
263250d58ff3SArtur Paszkiewicz 	rc = spdk_bdev_quiesce(&process->raid_bdev->bdev, &g_raid_if,
263350d58ff3SArtur Paszkiewicz 			       raid_bdev_process_finish_quiesced, process);
263450d58ff3SArtur Paszkiewicz 	if (rc != 0) {
263550d58ff3SArtur Paszkiewicz 		raid_bdev_process_finish_quiesced(ctx, rc);
263650d58ff3SArtur Paszkiewicz 	}
263750d58ff3SArtur Paszkiewicz }
263850d58ff3SArtur Paszkiewicz 
263950d58ff3SArtur Paszkiewicz static void
264050d58ff3SArtur Paszkiewicz raid_bdev_process_do_finish(struct raid_bdev_process *process)
264150d58ff3SArtur Paszkiewicz {
264250d58ff3SArtur Paszkiewicz 	spdk_thread_send_msg(spdk_thread_get_app_thread(), _raid_bdev_process_finish, process);
264350d58ff3SArtur Paszkiewicz }
264450d58ff3SArtur Paszkiewicz 
264550d58ff3SArtur Paszkiewicz static void raid_bdev_process_unlock_window_range(struct raid_bdev_process *process);
264650d58ff3SArtur Paszkiewicz static void raid_bdev_process_thread_run(struct raid_bdev_process *process);
264750d58ff3SArtur Paszkiewicz 
264850d58ff3SArtur Paszkiewicz static void
264950d58ff3SArtur Paszkiewicz raid_bdev_process_finish(struct raid_bdev_process *process, int status)
265050d58ff3SArtur Paszkiewicz {
265150d58ff3SArtur Paszkiewicz 	assert(spdk_get_thread() == process->thread);
265250d58ff3SArtur Paszkiewicz 
265350d58ff3SArtur Paszkiewicz 	if (process->status == 0) {
265450d58ff3SArtur Paszkiewicz 		process->status = status;
265550d58ff3SArtur Paszkiewicz 	}
265650d58ff3SArtur Paszkiewicz 
265750d58ff3SArtur Paszkiewicz 	if (process->state >= RAID_PROCESS_STATE_STOPPING) {
265850d58ff3SArtur Paszkiewicz 		return;
265950d58ff3SArtur Paszkiewicz 	}
266050d58ff3SArtur Paszkiewicz 
266150d58ff3SArtur Paszkiewicz 	assert(process->state == RAID_PROCESS_STATE_RUNNING);
266250d58ff3SArtur Paszkiewicz 	process->state = RAID_PROCESS_STATE_STOPPING;
266350d58ff3SArtur Paszkiewicz 
266450d58ff3SArtur Paszkiewicz 	if (process->window_range_locked) {
266550d58ff3SArtur Paszkiewicz 		raid_bdev_process_unlock_window_range(process);
266650d58ff3SArtur Paszkiewicz 	} else {
266750d58ff3SArtur Paszkiewicz 		raid_bdev_process_thread_run(process);
266850d58ff3SArtur Paszkiewicz 	}
266950d58ff3SArtur Paszkiewicz }
267050d58ff3SArtur Paszkiewicz 
267150d58ff3SArtur Paszkiewicz static void
267250d58ff3SArtur Paszkiewicz raid_bdev_process_window_range_unlocked(void *ctx, int status)
267350d58ff3SArtur Paszkiewicz {
267450d58ff3SArtur Paszkiewicz 	struct raid_bdev_process *process = ctx;
267550d58ff3SArtur Paszkiewicz 
267650d58ff3SArtur Paszkiewicz 	if (status != 0) {
267750d58ff3SArtur Paszkiewicz 		SPDK_ERRLOG("Failed to unlock LBA range: %s\n", spdk_strerror(-status));
267850d58ff3SArtur Paszkiewicz 		raid_bdev_process_finish(process, status);
267950d58ff3SArtur Paszkiewicz 		return;
268050d58ff3SArtur Paszkiewicz 	}
268150d58ff3SArtur Paszkiewicz 
268250d58ff3SArtur Paszkiewicz 	process->window_range_locked = false;
268350d58ff3SArtur Paszkiewicz 	process->window_offset += process->window_size;
268450d58ff3SArtur Paszkiewicz 
268550d58ff3SArtur Paszkiewicz 	raid_bdev_process_thread_run(process);
268650d58ff3SArtur Paszkiewicz }
268750d58ff3SArtur Paszkiewicz 
268850d58ff3SArtur Paszkiewicz static void
268950d58ff3SArtur Paszkiewicz raid_bdev_process_unlock_window_range(struct raid_bdev_process *process)
269050d58ff3SArtur Paszkiewicz {
269150d58ff3SArtur Paszkiewicz 	int rc;
269250d58ff3SArtur Paszkiewicz 
269350d58ff3SArtur Paszkiewicz 	assert(process->window_range_locked == true);
269450d58ff3SArtur Paszkiewicz 
269550d58ff3SArtur Paszkiewicz 	rc = spdk_bdev_unquiesce_range(&process->raid_bdev->bdev, &g_raid_if,
269650d58ff3SArtur Paszkiewicz 				       process->window_offset, process->max_window_size,
269750d58ff3SArtur Paszkiewicz 				       raid_bdev_process_window_range_unlocked, process);
269850d58ff3SArtur Paszkiewicz 	if (rc != 0) {
269950d58ff3SArtur Paszkiewicz 		raid_bdev_process_window_range_unlocked(process, rc);
270050d58ff3SArtur Paszkiewicz 	}
270150d58ff3SArtur Paszkiewicz }
270250d58ff3SArtur Paszkiewicz 
270350d58ff3SArtur Paszkiewicz static void
270450d58ff3SArtur Paszkiewicz raid_bdev_process_channels_update_done(struct spdk_io_channel_iter *i, int status)
270550d58ff3SArtur Paszkiewicz {
270650d58ff3SArtur Paszkiewicz 	struct raid_bdev_process *process = spdk_io_channel_iter_get_ctx(i);
270750d58ff3SArtur Paszkiewicz 
270850d58ff3SArtur Paszkiewicz 	raid_bdev_process_unlock_window_range(process);
270950d58ff3SArtur Paszkiewicz }
271050d58ff3SArtur Paszkiewicz 
271150d58ff3SArtur Paszkiewicz static void
271250d58ff3SArtur Paszkiewicz raid_bdev_process_channel_update(struct spdk_io_channel_iter *i)
271350d58ff3SArtur Paszkiewicz {
271450d58ff3SArtur Paszkiewicz 	struct raid_bdev_process *process = spdk_io_channel_iter_get_ctx(i);
271550d58ff3SArtur Paszkiewicz 	struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(i);
271650d58ff3SArtur Paszkiewicz 	struct raid_bdev_io_channel *raid_ch = spdk_io_channel_get_ctx(ch);
271750d58ff3SArtur Paszkiewicz 
271850d58ff3SArtur Paszkiewicz 	raid_ch->process.offset = process->window_offset + process->window_size;
271950d58ff3SArtur Paszkiewicz 
272050d58ff3SArtur Paszkiewicz 	spdk_for_each_channel_continue(i, 0);
272150d58ff3SArtur Paszkiewicz }
272250d58ff3SArtur Paszkiewicz 
272350d58ff3SArtur Paszkiewicz void
272450d58ff3SArtur Paszkiewicz raid_bdev_process_request_complete(struct raid_bdev_process_request *process_req, int status)
272550d58ff3SArtur Paszkiewicz {
272650d58ff3SArtur Paszkiewicz 	struct raid_bdev_process *process = process_req->process;
272750d58ff3SArtur Paszkiewicz 
272850d58ff3SArtur Paszkiewicz 	TAILQ_INSERT_TAIL(&process->requests, process_req, link);
272950d58ff3SArtur Paszkiewicz 
273050d58ff3SArtur Paszkiewicz 	assert(spdk_get_thread() == process->thread);
273150d58ff3SArtur Paszkiewicz 	assert(process->window_remaining >= process_req->num_blocks);
273250d58ff3SArtur Paszkiewicz 
273350d58ff3SArtur Paszkiewicz 	if (status != 0) {
273450d58ff3SArtur Paszkiewicz 		process->window_status = status;
273550d58ff3SArtur Paszkiewicz 	}
273650d58ff3SArtur Paszkiewicz 
273750d58ff3SArtur Paszkiewicz 	process->window_remaining -= process_req->num_blocks;
273850d58ff3SArtur Paszkiewicz 	if (process->window_remaining == 0) {
273950d58ff3SArtur Paszkiewicz 		if (process->window_status != 0) {
274050d58ff3SArtur Paszkiewicz 			raid_bdev_process_finish(process, process->window_status);
274150d58ff3SArtur Paszkiewicz 			return;
274250d58ff3SArtur Paszkiewicz 		}
274350d58ff3SArtur Paszkiewicz 
274450d58ff3SArtur Paszkiewicz 		spdk_for_each_channel(process->raid_bdev, raid_bdev_process_channel_update, process,
274550d58ff3SArtur Paszkiewicz 				      raid_bdev_process_channels_update_done);
274650d58ff3SArtur Paszkiewicz 	}
274750d58ff3SArtur Paszkiewicz }
274850d58ff3SArtur Paszkiewicz 
274950d58ff3SArtur Paszkiewicz static int
275050d58ff3SArtur Paszkiewicz raid_bdev_submit_process_request(struct raid_bdev_process *process, uint64_t offset_blocks,
275150d58ff3SArtur Paszkiewicz 				 uint32_t num_blocks)
275250d58ff3SArtur Paszkiewicz {
275350d58ff3SArtur Paszkiewicz 	struct raid_bdev *raid_bdev = process->raid_bdev;
275450d58ff3SArtur Paszkiewicz 	struct raid_bdev_process_request *process_req;
275550d58ff3SArtur Paszkiewicz 	int ret;
275650d58ff3SArtur Paszkiewicz 
275750d58ff3SArtur Paszkiewicz 	process_req = TAILQ_FIRST(&process->requests);
275850d58ff3SArtur Paszkiewicz 	if (process_req == NULL) {
275950d58ff3SArtur Paszkiewicz 		assert(process->window_remaining > 0);
276050d58ff3SArtur Paszkiewicz 		return 0;
276150d58ff3SArtur Paszkiewicz 	}
276250d58ff3SArtur Paszkiewicz 
276350d58ff3SArtur Paszkiewicz 	process_req->target = process->target;
276450d58ff3SArtur Paszkiewicz 	process_req->target_ch = process->raid_ch->process.target_ch;
276550d58ff3SArtur Paszkiewicz 	process_req->offset_blocks = offset_blocks;
276650d58ff3SArtur Paszkiewicz 	process_req->num_blocks = num_blocks;
276750d58ff3SArtur Paszkiewicz 	process_req->iov.iov_len = num_blocks * raid_bdev->bdev.blocklen;
276850d58ff3SArtur Paszkiewicz 
276950d58ff3SArtur Paszkiewicz 	ret = raid_bdev->module->submit_process_request(process_req, process->raid_ch);
277050d58ff3SArtur Paszkiewicz 	if (ret <= 0) {
277150d58ff3SArtur Paszkiewicz 		if (ret < 0) {
277250d58ff3SArtur Paszkiewicz 			SPDK_ERRLOG("Failed to submit process request on %s: %s\n",
277350d58ff3SArtur Paszkiewicz 				    raid_bdev->bdev.name, spdk_strerror(-ret));
277450d58ff3SArtur Paszkiewicz 			process->window_status = ret;
277550d58ff3SArtur Paszkiewicz 		}
277650d58ff3SArtur Paszkiewicz 		return ret;
277750d58ff3SArtur Paszkiewicz 	}
277850d58ff3SArtur Paszkiewicz 
277950d58ff3SArtur Paszkiewicz 	process_req->num_blocks = ret;
278050d58ff3SArtur Paszkiewicz 	TAILQ_REMOVE(&process->requests, process_req, link);
278150d58ff3SArtur Paszkiewicz 
278250d58ff3SArtur Paszkiewicz 	return ret;
278350d58ff3SArtur Paszkiewicz }
278450d58ff3SArtur Paszkiewicz 
278550d58ff3SArtur Paszkiewicz static void
278650d58ff3SArtur Paszkiewicz _raid_bdev_process_thread_run(struct raid_bdev_process *process)
278750d58ff3SArtur Paszkiewicz {
278850d58ff3SArtur Paszkiewicz 	struct raid_bdev *raid_bdev = process->raid_bdev;
278950d58ff3SArtur Paszkiewicz 	uint64_t offset = process->window_offset;
279050d58ff3SArtur Paszkiewicz 	const uint64_t offset_end = spdk_min(offset + process->max_window_size, raid_bdev->bdev.blockcnt);
279150d58ff3SArtur Paszkiewicz 	int ret;
279250d58ff3SArtur Paszkiewicz 
279350d58ff3SArtur Paszkiewicz 	while (offset < offset_end) {
279450d58ff3SArtur Paszkiewicz 		ret = raid_bdev_submit_process_request(process, offset, offset_end - offset);
279550d58ff3SArtur Paszkiewicz 		if (ret <= 0) {
279650d58ff3SArtur Paszkiewicz 			break;
279750d58ff3SArtur Paszkiewicz 		}
279850d58ff3SArtur Paszkiewicz 
279950d58ff3SArtur Paszkiewicz 		process->window_remaining += ret;
280050d58ff3SArtur Paszkiewicz 		offset += ret;
280150d58ff3SArtur Paszkiewicz 	}
280250d58ff3SArtur Paszkiewicz 
280350d58ff3SArtur Paszkiewicz 	if (process->window_remaining > 0) {
280450d58ff3SArtur Paszkiewicz 		process->window_size = process->window_remaining;
280550d58ff3SArtur Paszkiewicz 	} else {
280650d58ff3SArtur Paszkiewicz 		raid_bdev_process_finish(process, process->window_status);
280750d58ff3SArtur Paszkiewicz 	}
280850d58ff3SArtur Paszkiewicz }
280950d58ff3SArtur Paszkiewicz 
281050d58ff3SArtur Paszkiewicz static void
281150d58ff3SArtur Paszkiewicz raid_bdev_process_window_range_locked(void *ctx, int status)
281250d58ff3SArtur Paszkiewicz {
281350d58ff3SArtur Paszkiewicz 	struct raid_bdev_process *process = ctx;
281450d58ff3SArtur Paszkiewicz 
281550d58ff3SArtur Paszkiewicz 	if (status != 0) {
281650d58ff3SArtur Paszkiewicz 		SPDK_ERRLOG("Failed to lock LBA range: %s\n", spdk_strerror(-status));
281750d58ff3SArtur Paszkiewicz 		raid_bdev_process_finish(process, status);
281850d58ff3SArtur Paszkiewicz 		return;
281950d58ff3SArtur Paszkiewicz 	}
282050d58ff3SArtur Paszkiewicz 
282150d58ff3SArtur Paszkiewicz 	process->window_range_locked = true;
282250d58ff3SArtur Paszkiewicz 
282350d58ff3SArtur Paszkiewicz 	if (process->state == RAID_PROCESS_STATE_STOPPING) {
282450d58ff3SArtur Paszkiewicz 		raid_bdev_process_unlock_window_range(process);
282550d58ff3SArtur Paszkiewicz 		return;
282650d58ff3SArtur Paszkiewicz 	}
282750d58ff3SArtur Paszkiewicz 
282850d58ff3SArtur Paszkiewicz 	_raid_bdev_process_thread_run(process);
282950d58ff3SArtur Paszkiewicz }
283050d58ff3SArtur Paszkiewicz 
283189fd1730Sxupeng9 static bool
283289fd1730Sxupeng9 raid_bdev_process_consume_token(struct raid_bdev_process *process)
283389fd1730Sxupeng9 {
283489fd1730Sxupeng9 	struct raid_bdev *raid_bdev = process->raid_bdev;
283589fd1730Sxupeng9 	uint64_t now = spdk_get_ticks();
283689fd1730Sxupeng9 
283789fd1730Sxupeng9 	process->qos.bytes_available = spdk_min(process->qos.bytes_max,
283889fd1730Sxupeng9 						process->qos.bytes_available +
283989fd1730Sxupeng9 						(now - process->qos.last_tsc) * process->qos.bytes_per_tsc);
284089fd1730Sxupeng9 	process->qos.last_tsc = now;
284189fd1730Sxupeng9 	if (process->qos.bytes_available > 0.0) {
284289fd1730Sxupeng9 		process->qos.bytes_available -= process->window_size * raid_bdev->bdev.blocklen;
284389fd1730Sxupeng9 		return true;
284489fd1730Sxupeng9 	}
284589fd1730Sxupeng9 	return false;
284689fd1730Sxupeng9 }
284789fd1730Sxupeng9 
284889fd1730Sxupeng9 static bool
284989fd1730Sxupeng9 raid_bdev_process_lock_window_range(struct raid_bdev_process *process)
285089fd1730Sxupeng9 {
285189fd1730Sxupeng9 	struct raid_bdev *raid_bdev = process->raid_bdev;
285289fd1730Sxupeng9 	int rc;
285389fd1730Sxupeng9 
285489fd1730Sxupeng9 	assert(process->window_range_locked == false);
285589fd1730Sxupeng9 
285689fd1730Sxupeng9 	if (process->qos.enable_qos) {
285789fd1730Sxupeng9 		if (raid_bdev_process_consume_token(process)) {
285889fd1730Sxupeng9 			spdk_poller_pause(process->qos.process_continue_poller);
285989fd1730Sxupeng9 		} else {
286089fd1730Sxupeng9 			spdk_poller_resume(process->qos.process_continue_poller);
286189fd1730Sxupeng9 			return false;
286289fd1730Sxupeng9 		}
286389fd1730Sxupeng9 	}
286489fd1730Sxupeng9 
286589fd1730Sxupeng9 	rc = spdk_bdev_quiesce_range(&raid_bdev->bdev, &g_raid_if,
286689fd1730Sxupeng9 				     process->window_offset, process->max_window_size,
286789fd1730Sxupeng9 				     raid_bdev_process_window_range_locked, process);
286889fd1730Sxupeng9 	if (rc != 0) {
286989fd1730Sxupeng9 		raid_bdev_process_window_range_locked(process, rc);
287089fd1730Sxupeng9 	}
287189fd1730Sxupeng9 	return true;
287289fd1730Sxupeng9 }
287389fd1730Sxupeng9 
287489fd1730Sxupeng9 static int
287589fd1730Sxupeng9 raid_bdev_process_continue_poll(void *arg)
287689fd1730Sxupeng9 {
287789fd1730Sxupeng9 	struct raid_bdev_process *process = arg;
287889fd1730Sxupeng9 
287989fd1730Sxupeng9 	if (raid_bdev_process_lock_window_range(process)) {
288089fd1730Sxupeng9 		return SPDK_POLLER_BUSY;
288189fd1730Sxupeng9 	}
288289fd1730Sxupeng9 	return SPDK_POLLER_IDLE;
288389fd1730Sxupeng9 }
288489fd1730Sxupeng9 
288550d58ff3SArtur Paszkiewicz static void
288650d58ff3SArtur Paszkiewicz raid_bdev_process_thread_run(struct raid_bdev_process *process)
288750d58ff3SArtur Paszkiewicz {
288850d58ff3SArtur Paszkiewicz 	struct raid_bdev *raid_bdev = process->raid_bdev;
288950d58ff3SArtur Paszkiewicz 
289050d58ff3SArtur Paszkiewicz 	assert(spdk_get_thread() == process->thread);
289150d58ff3SArtur Paszkiewicz 	assert(process->window_remaining == 0);
289250d58ff3SArtur Paszkiewicz 	assert(process->window_range_locked == false);
289350d58ff3SArtur Paszkiewicz 
289450d58ff3SArtur Paszkiewicz 	if (process->state == RAID_PROCESS_STATE_STOPPING) {
289550d58ff3SArtur Paszkiewicz 		raid_bdev_process_do_finish(process);
289650d58ff3SArtur Paszkiewicz 		return;
289750d58ff3SArtur Paszkiewicz 	}
289850d58ff3SArtur Paszkiewicz 
289950d58ff3SArtur Paszkiewicz 	if (process->window_offset == raid_bdev->bdev.blockcnt) {
290050d58ff3SArtur Paszkiewicz 		SPDK_DEBUGLOG(bdev_raid, "process completed on %s\n", raid_bdev->bdev.name);
290150d58ff3SArtur Paszkiewicz 		raid_bdev_process_finish(process, 0);
290250d58ff3SArtur Paszkiewicz 		return;
290350d58ff3SArtur Paszkiewicz 	}
290450d58ff3SArtur Paszkiewicz 
290550d58ff3SArtur Paszkiewicz 	process->max_window_size = spdk_min(raid_bdev->bdev.blockcnt - process->window_offset,
290650d58ff3SArtur Paszkiewicz 					    process->max_window_size);
290789fd1730Sxupeng9 	raid_bdev_process_lock_window_range(process);
290850d58ff3SArtur Paszkiewicz }
290950d58ff3SArtur Paszkiewicz 
291050d58ff3SArtur Paszkiewicz static void
291150d58ff3SArtur Paszkiewicz raid_bdev_process_thread_init(void *ctx)
291250d58ff3SArtur Paszkiewicz {
291350d58ff3SArtur Paszkiewicz 	struct raid_bdev_process *process = ctx;
291450d58ff3SArtur Paszkiewicz 	struct raid_bdev *raid_bdev = process->raid_bdev;
291550d58ff3SArtur Paszkiewicz 	struct spdk_io_channel *ch;
291650d58ff3SArtur Paszkiewicz 
291750d58ff3SArtur Paszkiewicz 	process->thread = spdk_get_thread();
291850d58ff3SArtur Paszkiewicz 
291950d58ff3SArtur Paszkiewicz 	ch = spdk_get_io_channel(raid_bdev);
292050d58ff3SArtur Paszkiewicz 	if (ch == NULL) {
292150d58ff3SArtur Paszkiewicz 		process->status = -ENOMEM;
292250d58ff3SArtur Paszkiewicz 		raid_bdev_process_do_finish(process);
292350d58ff3SArtur Paszkiewicz 		return;
292450d58ff3SArtur Paszkiewicz 	}
292550d58ff3SArtur Paszkiewicz 
292650d58ff3SArtur Paszkiewicz 	process->raid_ch = spdk_io_channel_get_ctx(ch);
292750d58ff3SArtur Paszkiewicz 	process->state = RAID_PROCESS_STATE_RUNNING;
292850d58ff3SArtur Paszkiewicz 
292989fd1730Sxupeng9 	if (process->qos.enable_qos) {
293089fd1730Sxupeng9 		process->qos.process_continue_poller = SPDK_POLLER_REGISTER(raid_bdev_process_continue_poll,
293189fd1730Sxupeng9 						       process, 0);
293289fd1730Sxupeng9 		spdk_poller_pause(process->qos.process_continue_poller);
293389fd1730Sxupeng9 	}
293489fd1730Sxupeng9 
293550d58ff3SArtur Paszkiewicz 	SPDK_NOTICELOG("Started %s on raid bdev %s\n",
293650d58ff3SArtur Paszkiewicz 		       raid_bdev_process_to_str(process->type), raid_bdev->bdev.name);
293750d58ff3SArtur Paszkiewicz 
293850d58ff3SArtur Paszkiewicz 	raid_bdev_process_thread_run(process);
293950d58ff3SArtur Paszkiewicz }
294050d58ff3SArtur Paszkiewicz 
294150d58ff3SArtur Paszkiewicz static void
294250d58ff3SArtur Paszkiewicz raid_bdev_channels_abort_start_process_done(struct spdk_io_channel_iter *i, int status)
294350d58ff3SArtur Paszkiewicz {
294450d58ff3SArtur Paszkiewicz 	struct raid_bdev_process *process = spdk_io_channel_iter_get_ctx(i);
294550d58ff3SArtur Paszkiewicz 
294650d58ff3SArtur Paszkiewicz 	_raid_bdev_remove_base_bdev(process->target, NULL, NULL);
294750d58ff3SArtur Paszkiewicz 	raid_bdev_process_free(process);
294850d58ff3SArtur Paszkiewicz 
294950d58ff3SArtur Paszkiewicz 	/* TODO: update sb */
295050d58ff3SArtur Paszkiewicz }
295150d58ff3SArtur Paszkiewicz 
295250d58ff3SArtur Paszkiewicz static void
295350d58ff3SArtur Paszkiewicz raid_bdev_channel_abort_start_process(struct spdk_io_channel_iter *i)
295450d58ff3SArtur Paszkiewicz {
295550d58ff3SArtur Paszkiewicz 	struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(i);
295650d58ff3SArtur Paszkiewicz 	struct raid_bdev_io_channel *raid_ch = spdk_io_channel_get_ctx(ch);
295750d58ff3SArtur Paszkiewicz 
295850d58ff3SArtur Paszkiewicz 	raid_bdev_ch_process_cleanup(raid_ch);
295950d58ff3SArtur Paszkiewicz 
296050d58ff3SArtur Paszkiewicz 	spdk_for_each_channel_continue(i, 0);
296150d58ff3SArtur Paszkiewicz }
296250d58ff3SArtur Paszkiewicz 
296350d58ff3SArtur Paszkiewicz static void
296450d58ff3SArtur Paszkiewicz raid_bdev_channels_start_process_done(struct spdk_io_channel_iter *i, int status)
296550d58ff3SArtur Paszkiewicz {
296650d58ff3SArtur Paszkiewicz 	struct raid_bdev_process *process = spdk_io_channel_iter_get_ctx(i);
296750d58ff3SArtur Paszkiewicz 	struct raid_bdev *raid_bdev = process->raid_bdev;
296850d58ff3SArtur Paszkiewicz 	struct spdk_thread *thread;
296950d58ff3SArtur Paszkiewicz 	char thread_name[RAID_BDEV_SB_NAME_SIZE + 16];
297050d58ff3SArtur Paszkiewicz 
29711a587504SArtur Paszkiewicz 	if (status == 0 &&
29721a587504SArtur Paszkiewicz 	    (process->target->remove_scheduled || !process->target->is_configured ||
29731a587504SArtur Paszkiewicz 	     raid_bdev->num_base_bdevs_operational <= raid_bdev->min_base_bdevs_operational)) {
29741a587504SArtur Paszkiewicz 		/* a base bdev was removed before we got here */
29751a587504SArtur Paszkiewicz 		status = -ENODEV;
29761a587504SArtur Paszkiewicz 	}
29771a587504SArtur Paszkiewicz 
297850d58ff3SArtur Paszkiewicz 	if (status != 0) {
297950d58ff3SArtur Paszkiewicz 		SPDK_ERRLOG("Failed to start %s on %s: %s\n",
298050d58ff3SArtur Paszkiewicz 			    raid_bdev_process_to_str(process->type), raid_bdev->bdev.name,
298150d58ff3SArtur Paszkiewicz 			    spdk_strerror(-status));
298250d58ff3SArtur Paszkiewicz 		goto err;
298350d58ff3SArtur Paszkiewicz 	}
298450d58ff3SArtur Paszkiewicz 
298550d58ff3SArtur Paszkiewicz 	snprintf(thread_name, sizeof(thread_name), "%s_%s",
298650d58ff3SArtur Paszkiewicz 		 raid_bdev->bdev.name, raid_bdev_process_to_str(process->type));
298750d58ff3SArtur Paszkiewicz 
298850d58ff3SArtur Paszkiewicz 	thread = spdk_thread_create(thread_name, NULL);
298950d58ff3SArtur Paszkiewicz 	if (thread == NULL) {
299050d58ff3SArtur Paszkiewicz 		SPDK_ERRLOG("Failed to create %s thread for %s\n",
299150d58ff3SArtur Paszkiewicz 			    raid_bdev_process_to_str(process->type), raid_bdev->bdev.name);
299250d58ff3SArtur Paszkiewicz 		goto err;
299350d58ff3SArtur Paszkiewicz 	}
299450d58ff3SArtur Paszkiewicz 
299550d58ff3SArtur Paszkiewicz 	raid_bdev->process = process;
299650d58ff3SArtur Paszkiewicz 
299750d58ff3SArtur Paszkiewicz 	spdk_thread_send_msg(thread, raid_bdev_process_thread_init, process);
299850d58ff3SArtur Paszkiewicz 
299950d58ff3SArtur Paszkiewicz 	return;
300050d58ff3SArtur Paszkiewicz err:
300150d58ff3SArtur Paszkiewicz 	spdk_for_each_channel(process->raid_bdev, raid_bdev_channel_abort_start_process, process,
300250d58ff3SArtur Paszkiewicz 			      raid_bdev_channels_abort_start_process_done);
300350d58ff3SArtur Paszkiewicz }
300450d58ff3SArtur Paszkiewicz 
300550d58ff3SArtur Paszkiewicz static void
300650d58ff3SArtur Paszkiewicz raid_bdev_channel_start_process(struct spdk_io_channel_iter *i)
300750d58ff3SArtur Paszkiewicz {
300850d58ff3SArtur Paszkiewicz 	struct raid_bdev_process *process = spdk_io_channel_iter_get_ctx(i);
300950d58ff3SArtur Paszkiewicz 	struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(i);
301050d58ff3SArtur Paszkiewicz 	struct raid_bdev_io_channel *raid_ch = spdk_io_channel_get_ctx(ch);
301150d58ff3SArtur Paszkiewicz 	int rc;
301250d58ff3SArtur Paszkiewicz 
301350d58ff3SArtur Paszkiewicz 	rc = raid_bdev_ch_process_setup(raid_ch, process);
301450d58ff3SArtur Paszkiewicz 
301550d58ff3SArtur Paszkiewicz 	spdk_for_each_channel_continue(i, rc);
301650d58ff3SArtur Paszkiewicz }
301750d58ff3SArtur Paszkiewicz 
301850d58ff3SArtur Paszkiewicz static void
301950d58ff3SArtur Paszkiewicz raid_bdev_process_start(struct raid_bdev_process *process)
302050d58ff3SArtur Paszkiewicz {
302150d58ff3SArtur Paszkiewicz 	struct raid_bdev *raid_bdev = process->raid_bdev;
302250d58ff3SArtur Paszkiewicz 
302350d58ff3SArtur Paszkiewicz 	assert(raid_bdev->module->submit_process_request != NULL);
302450d58ff3SArtur Paszkiewicz 
302550d58ff3SArtur Paszkiewicz 	spdk_for_each_channel(raid_bdev, raid_bdev_channel_start_process, process,
302650d58ff3SArtur Paszkiewicz 			      raid_bdev_channels_start_process_done);
302750d58ff3SArtur Paszkiewicz }
302850d58ff3SArtur Paszkiewicz 
302950d58ff3SArtur Paszkiewicz static void
303050d58ff3SArtur Paszkiewicz raid_bdev_process_request_free(struct raid_bdev_process_request *process_req)
303150d58ff3SArtur Paszkiewicz {
303250d58ff3SArtur Paszkiewicz 	spdk_dma_free(process_req->iov.iov_base);
303350d58ff3SArtur Paszkiewicz 	spdk_dma_free(process_req->md_buf);
303450d58ff3SArtur Paszkiewicz 	free(process_req);
303550d58ff3SArtur Paszkiewicz }
303650d58ff3SArtur Paszkiewicz 
303750d58ff3SArtur Paszkiewicz static struct raid_bdev_process_request *
303850d58ff3SArtur Paszkiewicz raid_bdev_process_alloc_request(struct raid_bdev_process *process)
303950d58ff3SArtur Paszkiewicz {
304050d58ff3SArtur Paszkiewicz 	struct raid_bdev *raid_bdev = process->raid_bdev;
304150d58ff3SArtur Paszkiewicz 	struct raid_bdev_process_request *process_req;
304250d58ff3SArtur Paszkiewicz 
304350d58ff3SArtur Paszkiewicz 	process_req = calloc(1, sizeof(*process_req));
304450d58ff3SArtur Paszkiewicz 	if (process_req == NULL) {
304550d58ff3SArtur Paszkiewicz 		return NULL;
304650d58ff3SArtur Paszkiewicz 	}
304750d58ff3SArtur Paszkiewicz 
304850d58ff3SArtur Paszkiewicz 	process_req->process = process;
304950d58ff3SArtur Paszkiewicz 	process_req->iov.iov_len = process->max_window_size * raid_bdev->bdev.blocklen;
305050d58ff3SArtur Paszkiewicz 	process_req->iov.iov_base = spdk_dma_malloc(process_req->iov.iov_len, 4096, 0);
305150d58ff3SArtur Paszkiewicz 	if (process_req->iov.iov_base == NULL) {
305250d58ff3SArtur Paszkiewicz 		free(process_req);
305350d58ff3SArtur Paszkiewicz 		return NULL;
305450d58ff3SArtur Paszkiewicz 	}
305550d58ff3SArtur Paszkiewicz 	if (spdk_bdev_is_md_separate(&raid_bdev->bdev)) {
305650d58ff3SArtur Paszkiewicz 		process_req->md_buf = spdk_dma_malloc(process->max_window_size * raid_bdev->bdev.md_len, 4096, 0);
305750d58ff3SArtur Paszkiewicz 		if (process_req->md_buf == NULL) {
305850d58ff3SArtur Paszkiewicz 			raid_bdev_process_request_free(process_req);
305950d58ff3SArtur Paszkiewicz 			return NULL;
306050d58ff3SArtur Paszkiewicz 		}
306150d58ff3SArtur Paszkiewicz 	}
306250d58ff3SArtur Paszkiewicz 
306350d58ff3SArtur Paszkiewicz 	return process_req;
306450d58ff3SArtur Paszkiewicz }
306550d58ff3SArtur Paszkiewicz 
306650d58ff3SArtur Paszkiewicz static void
306750d58ff3SArtur Paszkiewicz raid_bdev_process_free(struct raid_bdev_process *process)
306850d58ff3SArtur Paszkiewicz {
306950d58ff3SArtur Paszkiewicz 	struct raid_bdev_process_request *process_req;
307050d58ff3SArtur Paszkiewicz 
307150d58ff3SArtur Paszkiewicz 	while ((process_req = TAILQ_FIRST(&process->requests)) != NULL) {
307250d58ff3SArtur Paszkiewicz 		TAILQ_REMOVE(&process->requests, process_req, link);
307350d58ff3SArtur Paszkiewicz 		raid_bdev_process_request_free(process_req);
307450d58ff3SArtur Paszkiewicz 	}
307550d58ff3SArtur Paszkiewicz 
307650d58ff3SArtur Paszkiewicz 	free(process);
307750d58ff3SArtur Paszkiewicz }
307850d58ff3SArtur Paszkiewicz 
307950d58ff3SArtur Paszkiewicz static struct raid_bdev_process *
308050d58ff3SArtur Paszkiewicz raid_bdev_process_alloc(struct raid_bdev *raid_bdev, enum raid_process_type type,
308150d58ff3SArtur Paszkiewicz 			struct raid_base_bdev_info *target)
308250d58ff3SArtur Paszkiewicz {
308350d58ff3SArtur Paszkiewicz 	struct raid_bdev_process *process;
308450d58ff3SArtur Paszkiewicz 	struct raid_bdev_process_request *process_req;
308550d58ff3SArtur Paszkiewicz 	int i;
308650d58ff3SArtur Paszkiewicz 
308750d58ff3SArtur Paszkiewicz 	process = calloc(1, sizeof(*process));
308850d58ff3SArtur Paszkiewicz 	if (process == NULL) {
308950d58ff3SArtur Paszkiewicz 		return NULL;
309050d58ff3SArtur Paszkiewicz 	}
309150d58ff3SArtur Paszkiewicz 
309250d58ff3SArtur Paszkiewicz 	process->raid_bdev = raid_bdev;
309350d58ff3SArtur Paszkiewicz 	process->type = type;
309450d58ff3SArtur Paszkiewicz 	process->target = target;
3095f39350beSArtur Paszkiewicz 	process->max_window_size = spdk_max(spdk_divide_round_up(g_opts.process_window_size_kb * 1024UL,
3096bb374988SArtur Paszkiewicz 					    spdk_bdev_get_data_block_size(&raid_bdev->bdev)),
309750d58ff3SArtur Paszkiewicz 					    raid_bdev->bdev.write_unit_size);
309850d58ff3SArtur Paszkiewicz 	TAILQ_INIT(&process->requests);
30999d2b7b41SArtur Paszkiewicz 	TAILQ_INIT(&process->finish_actions);
310050d58ff3SArtur Paszkiewicz 
310189fd1730Sxupeng9 	if (g_opts.process_max_bandwidth_mb_sec != 0) {
310289fd1730Sxupeng9 		process->qos.enable_qos = true;
310389fd1730Sxupeng9 		process->qos.last_tsc = spdk_get_ticks();
310489fd1730Sxupeng9 		process->qos.bytes_per_tsc = g_opts.process_max_bandwidth_mb_sec * 1024 * 1024.0 /
310589fd1730Sxupeng9 					     spdk_get_ticks_hz();
310689fd1730Sxupeng9 		process->qos.bytes_max = g_opts.process_max_bandwidth_mb_sec * 1024 * 1024.0 / SPDK_SEC_TO_MSEC;
310789fd1730Sxupeng9 		process->qos.bytes_available = 0.0;
310889fd1730Sxupeng9 	}
310989fd1730Sxupeng9 
311050d58ff3SArtur Paszkiewicz 	for (i = 0; i < RAID_BDEV_PROCESS_MAX_QD; i++) {
311150d58ff3SArtur Paszkiewicz 		process_req = raid_bdev_process_alloc_request(process);
311250d58ff3SArtur Paszkiewicz 		if (process_req == NULL) {
311350d58ff3SArtur Paszkiewicz 			raid_bdev_process_free(process);
311450d58ff3SArtur Paszkiewicz 			return NULL;
311550d58ff3SArtur Paszkiewicz 		}
311650d58ff3SArtur Paszkiewicz 
311750d58ff3SArtur Paszkiewicz 		TAILQ_INSERT_TAIL(&process->requests, process_req, link);
311850d58ff3SArtur Paszkiewicz 	}
311950d58ff3SArtur Paszkiewicz 
312050d58ff3SArtur Paszkiewicz 	return process;
312150d58ff3SArtur Paszkiewicz }
312250d58ff3SArtur Paszkiewicz 
312350d58ff3SArtur Paszkiewicz static int
312450d58ff3SArtur Paszkiewicz raid_bdev_start_rebuild(struct raid_base_bdev_info *target)
312550d58ff3SArtur Paszkiewicz {
312650d58ff3SArtur Paszkiewicz 	struct raid_bdev_process *process;
312750d58ff3SArtur Paszkiewicz 
312850d58ff3SArtur Paszkiewicz 	assert(spdk_get_thread() == spdk_thread_get_app_thread());
312950d58ff3SArtur Paszkiewicz 
313050d58ff3SArtur Paszkiewicz 	process = raid_bdev_process_alloc(target->raid_bdev, RAID_PROCESS_REBUILD, target);
313150d58ff3SArtur Paszkiewicz 	if (process == NULL) {
313250d58ff3SArtur Paszkiewicz 		return -ENOMEM;
313350d58ff3SArtur Paszkiewicz 	}
313450d58ff3SArtur Paszkiewicz 
313550d58ff3SArtur Paszkiewicz 	raid_bdev_process_start(process);
313650d58ff3SArtur Paszkiewicz 
313750d58ff3SArtur Paszkiewicz 	return 0;
313850d58ff3SArtur Paszkiewicz }
313950d58ff3SArtur Paszkiewicz 
3140a6708553SArtur Paszkiewicz static void raid_bdev_configure_base_bdev_cont(struct raid_base_bdev_info *base_info);
3141a6708553SArtur Paszkiewicz 
3142a6708553SArtur Paszkiewicz static void
3143a6708553SArtur Paszkiewicz _raid_bdev_configure_base_bdev_cont(struct spdk_io_channel_iter *i, int status)
3144a6708553SArtur Paszkiewicz {
3145a6708553SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info = spdk_io_channel_iter_get_ctx(i);
3146a6708553SArtur Paszkiewicz 
3147a6708553SArtur Paszkiewicz 	raid_bdev_configure_base_bdev_cont(base_info);
3148a6708553SArtur Paszkiewicz }
3149a6708553SArtur Paszkiewicz 
3150a6708553SArtur Paszkiewicz static void
3151a6708553SArtur Paszkiewicz raid_bdev_ch_sync(struct spdk_io_channel_iter *i)
3152a6708553SArtur Paszkiewicz {
3153a6708553SArtur Paszkiewicz 	spdk_for_each_channel_continue(i, 0);
3154a6708553SArtur Paszkiewicz }
3155a6708553SArtur Paszkiewicz 
315650d58ff3SArtur Paszkiewicz static void
31579222ff97SArtur Paszkiewicz raid_bdev_configure_base_bdev_cont(struct raid_base_bdev_info *base_info)
31589222ff97SArtur Paszkiewicz {
31599222ff97SArtur Paszkiewicz 	struct raid_bdev *raid_bdev = base_info->raid_bdev;
3160fc2398dfSArtur Paszkiewicz 	raid_base_bdev_cb configure_cb;
31619222ff97SArtur Paszkiewicz 	int rc;
31629222ff97SArtur Paszkiewicz 
3163a6708553SArtur Paszkiewicz 	if (raid_bdev->num_base_bdevs_discovered == raid_bdev->num_base_bdevs_operational &&
3164a6708553SArtur Paszkiewicz 	    base_info->is_process_target == false) {
316550d58ff3SArtur Paszkiewicz 		/* TODO: defer if rebuild in progress on another base bdev */
316650d58ff3SArtur Paszkiewicz 		assert(raid_bdev->process == NULL);
3167a6708553SArtur Paszkiewicz 		assert(raid_bdev->state == RAID_BDEV_STATE_ONLINE);
3168a6708553SArtur Paszkiewicz 		base_info->is_process_target = true;
3169a6708553SArtur Paszkiewicz 		/* To assure is_process_target is set before is_configured when checked in raid_bdev_create_cb() */
3170a6708553SArtur Paszkiewicz 		spdk_for_each_channel(raid_bdev, raid_bdev_ch_sync, base_info, _raid_bdev_configure_base_bdev_cont);
3171a6708553SArtur Paszkiewicz 		return;
3172a6708553SArtur Paszkiewicz 	}
317350d58ff3SArtur Paszkiewicz 
31749222ff97SArtur Paszkiewicz 	base_info->is_configured = true;
31759222ff97SArtur Paszkiewicz 
31769222ff97SArtur Paszkiewicz 	raid_bdev->num_base_bdevs_discovered++;
31779222ff97SArtur Paszkiewicz 	assert(raid_bdev->num_base_bdevs_discovered <= raid_bdev->num_base_bdevs);
3178255d0786SArtur Paszkiewicz 	assert(raid_bdev->num_base_bdevs_operational <= raid_bdev->num_base_bdevs);
3179255d0786SArtur Paszkiewicz 	assert(raid_bdev->num_base_bdevs_operational >= raid_bdev->min_base_bdevs_operational);
31809222ff97SArtur Paszkiewicz 
3181fc2398dfSArtur Paszkiewicz 	configure_cb = base_info->configure_cb;
3182fc2398dfSArtur Paszkiewicz 	base_info->configure_cb = NULL;
3183255d0786SArtur Paszkiewicz 	/*
3184255d0786SArtur Paszkiewicz 	 * Configure the raid bdev when the number of discovered base bdevs reaches the number
3185255d0786SArtur Paszkiewicz 	 * of base bdevs we know to be operational members of the array. Usually this is equal
3186255d0786SArtur Paszkiewicz 	 * to the total number of base bdevs (num_base_bdevs) but can be less - when the array is
3187255d0786SArtur Paszkiewicz 	 * degraded.
3188255d0786SArtur Paszkiewicz 	 */
3189255d0786SArtur Paszkiewicz 	if (raid_bdev->num_base_bdevs_discovered == raid_bdev->num_base_bdevs_operational) {
3190fc2398dfSArtur Paszkiewicz 		rc = raid_bdev_configure(raid_bdev, configure_cb, base_info->configure_cb_ctx);
31919222ff97SArtur Paszkiewicz 		if (rc != 0) {
31929222ff97SArtur Paszkiewicz 			SPDK_ERRLOG("Failed to configure raid bdev: %s\n", spdk_strerror(-rc));
31935558f3f5SArtur Paszkiewicz 		} else {
3194fc2398dfSArtur Paszkiewicz 			configure_cb = NULL;
31959222ff97SArtur Paszkiewicz 		}
3196a6708553SArtur Paszkiewicz 	} else if (base_info->is_process_target) {
319750d58ff3SArtur Paszkiewicz 		raid_bdev->num_base_bdevs_operational++;
319850d58ff3SArtur Paszkiewicz 		rc = raid_bdev_start_rebuild(base_info);
319950d58ff3SArtur Paszkiewicz 		if (rc != 0) {
320050d58ff3SArtur Paszkiewicz 			SPDK_ERRLOG("Failed to start rebuild: %s\n", spdk_strerror(-rc));
320150d58ff3SArtur Paszkiewicz 			_raid_bdev_remove_base_bdev(base_info, NULL, NULL);
320250d58ff3SArtur Paszkiewicz 		}
3203887b8ec4SArtur Paszkiewicz 	} else {
3204887b8ec4SArtur Paszkiewicz 		rc = 0;
3205887b8ec4SArtur Paszkiewicz 	}
3206887b8ec4SArtur Paszkiewicz 
3207fc2398dfSArtur Paszkiewicz 	if (configure_cb != NULL) {
3208fc2398dfSArtur Paszkiewicz 		configure_cb(base_info->configure_cb_ctx, rc);
32099222ff97SArtur Paszkiewicz 	}
32109222ff97SArtur Paszkiewicz }
32119222ff97SArtur Paszkiewicz 
3212dafdb289SArtur Paszkiewicz static void raid_bdev_examine_sb(const struct raid_bdev_superblock *sb, struct spdk_bdev *bdev,
3213dafdb289SArtur Paszkiewicz 				 raid_base_bdev_cb cb_fn, void *cb_ctx);
3214dafdb289SArtur Paszkiewicz 
32159222ff97SArtur Paszkiewicz static void
32169222ff97SArtur Paszkiewicz raid_bdev_configure_base_bdev_check_sb_cb(const struct raid_bdev_superblock *sb, int status,
32179222ff97SArtur Paszkiewicz 		void *ctx)
32189222ff97SArtur Paszkiewicz {
32199222ff97SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info = ctx;
3220fc2398dfSArtur Paszkiewicz 	raid_base_bdev_cb configure_cb = base_info->configure_cb;
32219222ff97SArtur Paszkiewicz 
32229222ff97SArtur Paszkiewicz 	switch (status) {
32239222ff97SArtur Paszkiewicz 	case 0:
32249222ff97SArtur Paszkiewicz 		/* valid superblock found */
3225fc2398dfSArtur Paszkiewicz 		base_info->configure_cb = NULL;
3226dafdb289SArtur Paszkiewicz 		if (spdk_uuid_compare(&base_info->raid_bdev->bdev.uuid, &sb->uuid) == 0) {
3227dafdb289SArtur Paszkiewicz 			struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(base_info->desc);
3228dafdb289SArtur Paszkiewicz 
3229dafdb289SArtur Paszkiewicz 			raid_bdev_free_base_bdev_resource(base_info);
3230fc2398dfSArtur Paszkiewicz 			raid_bdev_examine_sb(sb, bdev, configure_cb, base_info->configure_cb_ctx);
3231dafdb289SArtur Paszkiewicz 			return;
3232dafdb289SArtur Paszkiewicz 		}
3233dafdb289SArtur Paszkiewicz 		SPDK_ERRLOG("Superblock of a different raid bdev found on bdev %s\n", base_info->name);
3234887b8ec4SArtur Paszkiewicz 		status = -EEXIST;
32359222ff97SArtur Paszkiewicz 		raid_bdev_free_base_bdev_resource(base_info);
32369222ff97SArtur Paszkiewicz 		break;
32379222ff97SArtur Paszkiewicz 	case -EINVAL:
32389222ff97SArtur Paszkiewicz 		/* no valid superblock */
32399222ff97SArtur Paszkiewicz 		raid_bdev_configure_base_bdev_cont(base_info);
3240887b8ec4SArtur Paszkiewicz 		return;
32419222ff97SArtur Paszkiewicz 	default:
32429222ff97SArtur Paszkiewicz 		SPDK_ERRLOG("Failed to examine bdev %s: %s\n",
32439222ff97SArtur Paszkiewicz 			    base_info->name, spdk_strerror(-status));
32449222ff97SArtur Paszkiewicz 		break;
32459222ff97SArtur Paszkiewicz 	}
3246887b8ec4SArtur Paszkiewicz 
3247fc2398dfSArtur Paszkiewicz 	if (configure_cb != NULL) {
3248fc2398dfSArtur Paszkiewicz 		base_info->configure_cb = NULL;
3249fc2398dfSArtur Paszkiewicz 		configure_cb(base_info->configure_cb_ctx, status);
3250887b8ec4SArtur Paszkiewicz 	}
32519222ff97SArtur Paszkiewicz }
32529222ff97SArtur Paszkiewicz 
325307fe6a43SSeth Howell static int
3254887b8ec4SArtur Paszkiewicz raid_bdev_configure_base_bdev(struct raid_base_bdev_info *base_info, bool existing,
3255887b8ec4SArtur Paszkiewicz 			      raid_base_bdev_cb cb_fn, void *cb_ctx)
325607fe6a43SSeth Howell {
325726861b70SArtur Paszkiewicz 	struct raid_bdev *raid_bdev = base_info->raid_bdev;
3258dccdd1e5SArtur Paszkiewicz 	struct spdk_bdev_desc *desc;
3259dccdd1e5SArtur Paszkiewicz 	struct spdk_bdev *bdev;
32608a6bb6a8SArtur Paszkiewicz 	const struct spdk_uuid *bdev_uuid;
326107fe6a43SSeth Howell 	int rc;
326207fe6a43SSeth Howell 
32634dd2a0d3SArtur Paszkiewicz 	assert(spdk_get_thread() == spdk_thread_get_app_thread());
32648d1993a5SArtur Paszkiewicz 	assert(base_info->desc == NULL);
326507fe6a43SSeth Howell 
32668a6bb6a8SArtur Paszkiewicz 	/*
32678a6bb6a8SArtur Paszkiewicz 	 * Base bdev can be added by name or uuid. Here we assure both properties are set and valid
32688a6bb6a8SArtur Paszkiewicz 	 * before claiming the bdev.
32698a6bb6a8SArtur Paszkiewicz 	 */
32708a6bb6a8SArtur Paszkiewicz 
32718a6bb6a8SArtur Paszkiewicz 	if (!spdk_uuid_is_null(&base_info->uuid)) {
32728a6bb6a8SArtur Paszkiewicz 		char uuid_str[SPDK_UUID_STRING_LEN];
32738a6bb6a8SArtur Paszkiewicz 		const char *bdev_name;
32748a6bb6a8SArtur Paszkiewicz 
32758a6bb6a8SArtur Paszkiewicz 		spdk_uuid_fmt_lower(uuid_str, sizeof(uuid_str), &base_info->uuid);
32768a6bb6a8SArtur Paszkiewicz 
32778a6bb6a8SArtur Paszkiewicz 		/* UUID of a bdev is registered as its alias */
32788a6bb6a8SArtur Paszkiewicz 		bdev = spdk_bdev_get_by_name(uuid_str);
32798a6bb6a8SArtur Paszkiewicz 		if (bdev == NULL) {
32808a6bb6a8SArtur Paszkiewicz 			return -ENODEV;
32818a6bb6a8SArtur Paszkiewicz 		}
32828a6bb6a8SArtur Paszkiewicz 
32838a6bb6a8SArtur Paszkiewicz 		bdev_name = spdk_bdev_get_name(bdev);
32848a6bb6a8SArtur Paszkiewicz 
32858a6bb6a8SArtur Paszkiewicz 		if (base_info->name == NULL) {
32869222ff97SArtur Paszkiewicz 			assert(existing == true);
32878a6bb6a8SArtur Paszkiewicz 			base_info->name = strdup(bdev_name);
32888a6bb6a8SArtur Paszkiewicz 			if (base_info->name == NULL) {
32898a6bb6a8SArtur Paszkiewicz 				return -ENOMEM;
32908a6bb6a8SArtur Paszkiewicz 			}
32918a6bb6a8SArtur Paszkiewicz 		} else if (strcmp(base_info->name, bdev_name) != 0) {
32928a6bb6a8SArtur Paszkiewicz 			SPDK_ERRLOG("Name mismatch for base bdev '%s' - expected '%s'\n",
32938a6bb6a8SArtur Paszkiewicz 				    bdev_name, base_info->name);
32948a6bb6a8SArtur Paszkiewicz 			return -EINVAL;
32958a6bb6a8SArtur Paszkiewicz 		}
32968a6bb6a8SArtur Paszkiewicz 	}
32978a6bb6a8SArtur Paszkiewicz 
32988a6bb6a8SArtur Paszkiewicz 	assert(base_info->name != NULL);
32998a6bb6a8SArtur Paszkiewicz 
3300dccdd1e5SArtur Paszkiewicz 	rc = spdk_bdev_open_ext(base_info->name, true, raid_bdev_event_base_bdev, NULL, &desc);
330107fe6a43SSeth Howell 	if (rc != 0) {
3302bd190d88SShuhei Matsumoto 		if (rc != -ENODEV) {
3303dccdd1e5SArtur Paszkiewicz 			SPDK_ERRLOG("Unable to create desc on bdev '%s'\n", base_info->name);
3304bd190d88SShuhei Matsumoto 		}
330507fe6a43SSeth Howell 		return rc;
330607fe6a43SSeth Howell 	}
330707fe6a43SSeth Howell 
3308dccdd1e5SArtur Paszkiewicz 	bdev = spdk_bdev_desc_get_bdev(desc);
33098a6bb6a8SArtur Paszkiewicz 	bdev_uuid = spdk_bdev_get_uuid(bdev);
33108a6bb6a8SArtur Paszkiewicz 
33118a6bb6a8SArtur Paszkiewicz 	if (spdk_uuid_is_null(&base_info->uuid)) {
33128a6bb6a8SArtur Paszkiewicz 		spdk_uuid_copy(&base_info->uuid, bdev_uuid);
33138a6bb6a8SArtur Paszkiewicz 	} else if (spdk_uuid_compare(&base_info->uuid, bdev_uuid) != 0) {
33148a6bb6a8SArtur Paszkiewicz 		SPDK_ERRLOG("UUID mismatch for base bdev '%s'\n", base_info->name);
33158a6bb6a8SArtur Paszkiewicz 		spdk_bdev_close(desc);
33168a6bb6a8SArtur Paszkiewicz 		return -EINVAL;
33178a6bb6a8SArtur Paszkiewicz 	}
3318dccdd1e5SArtur Paszkiewicz 
3319dccdd1e5SArtur Paszkiewicz 	rc = spdk_bdev_module_claim_bdev(bdev, NULL, &g_raid_if);
3320dccdd1e5SArtur Paszkiewicz 	if (rc != 0) {
3321dccdd1e5SArtur Paszkiewicz 		SPDK_ERRLOG("Unable to claim this bdev as it is already claimed\n");
3322dccdd1e5SArtur Paszkiewicz 		spdk_bdev_close(desc);
3323dccdd1e5SArtur Paszkiewicz 		return rc;
3324dccdd1e5SArtur Paszkiewicz 	}
3325dccdd1e5SArtur Paszkiewicz 
3326dccdd1e5SArtur Paszkiewicz 	SPDK_DEBUGLOG(bdev_raid, "bdev %s is claimed\n", bdev->name);
3327dccdd1e5SArtur Paszkiewicz 
332877b8f7b6SArtur Paszkiewicz 	base_info->app_thread_ch = spdk_bdev_get_io_channel(desc);
332977b8f7b6SArtur Paszkiewicz 	if (base_info->app_thread_ch == NULL) {
333077b8f7b6SArtur Paszkiewicz 		SPDK_ERRLOG("Failed to get io channel\n");
333177b8f7b6SArtur Paszkiewicz 		spdk_bdev_module_release_bdev(bdev);
333277b8f7b6SArtur Paszkiewicz 		spdk_bdev_close(desc);
333377b8f7b6SArtur Paszkiewicz 		return -ENOMEM;
333477b8f7b6SArtur Paszkiewicz 	}
333577b8f7b6SArtur Paszkiewicz 
3336dccdd1e5SArtur Paszkiewicz 	base_info->desc = desc;
3337c9224e26SShuhei Matsumoto 	base_info->blockcnt = bdev->blockcnt;
333807fe6a43SSeth Howell 
33393bb8256aSArtur Paszkiewicz 	if (raid_bdev->superblock_enabled) {
33408a6bb6a8SArtur Paszkiewicz 		uint64_t data_offset;
3341deed7d2fSArtur Paszkiewicz 
33428a6bb6a8SArtur Paszkiewicz 		if (base_info->data_offset == 0) {
3343bb374988SArtur Paszkiewicz 			assert((RAID_BDEV_MIN_DATA_OFFSET_SIZE % spdk_bdev_get_data_block_size(bdev)) == 0);
3344bb374988SArtur Paszkiewicz 			data_offset = RAID_BDEV_MIN_DATA_OFFSET_SIZE / spdk_bdev_get_data_block_size(bdev);
33458a6bb6a8SArtur Paszkiewicz 		} else {
33468a6bb6a8SArtur Paszkiewicz 			data_offset = base_info->data_offset;
33478a6bb6a8SArtur Paszkiewicz 		}
33488a6bb6a8SArtur Paszkiewicz 
33498a6bb6a8SArtur Paszkiewicz 		if (bdev->optimal_io_boundary != 0) {
33508a6bb6a8SArtur Paszkiewicz 			data_offset = spdk_divide_round_up(data_offset,
3351deed7d2fSArtur Paszkiewicz 							   bdev->optimal_io_boundary) * bdev->optimal_io_boundary;
33528a6bb6a8SArtur Paszkiewicz 			if (base_info->data_offset != 0 && base_info->data_offset != data_offset) {
33538a6bb6a8SArtur Paszkiewicz 				SPDK_WARNLOG("Data offset %lu on bdev '%s' is different than optimal value %lu\n",
33548a6bb6a8SArtur Paszkiewicz 					     base_info->data_offset, base_info->name, data_offset);
33558a6bb6a8SArtur Paszkiewicz 				data_offset = base_info->data_offset;
33568a6bb6a8SArtur Paszkiewicz 			}
33578a6bb6a8SArtur Paszkiewicz 		}
33588a6bb6a8SArtur Paszkiewicz 
33598a6bb6a8SArtur Paszkiewicz 		base_info->data_offset = data_offset;
3360deed7d2fSArtur Paszkiewicz 	}
3361deed7d2fSArtur Paszkiewicz 
3362deed7d2fSArtur Paszkiewicz 	if (base_info->data_offset >= bdev->blockcnt) {
3363deed7d2fSArtur Paszkiewicz 		SPDK_ERRLOG("Data offset %lu exceeds base bdev capacity %lu on bdev '%s'\n",
3364deed7d2fSArtur Paszkiewicz 			    base_info->data_offset, bdev->blockcnt, base_info->name);
33658a6bb6a8SArtur Paszkiewicz 		rc = -EINVAL;
33668a6bb6a8SArtur Paszkiewicz 		goto out;
3367deed7d2fSArtur Paszkiewicz 	}
3368deed7d2fSArtur Paszkiewicz 
33698a6bb6a8SArtur Paszkiewicz 	if (base_info->data_size == 0) {
3370deed7d2fSArtur Paszkiewicz 		base_info->data_size = bdev->blockcnt - base_info->data_offset;
33718a6bb6a8SArtur Paszkiewicz 	} else if (base_info->data_offset + base_info->data_size > bdev->blockcnt) {
33728a6bb6a8SArtur Paszkiewicz 		SPDK_ERRLOG("Data offset and size exceeds base bdev capacity %lu on bdev '%s'\n",
33738a6bb6a8SArtur Paszkiewicz 			    bdev->blockcnt, base_info->name);
33748a6bb6a8SArtur Paszkiewicz 		rc = -EINVAL;
33758a6bb6a8SArtur Paszkiewicz 		goto out;
3376deed7d2fSArtur Paszkiewicz 	}
3377deed7d2fSArtur Paszkiewicz 
3378192db8deSSlawomir Ptak 	if (!raid_bdev->module->dif_supported && spdk_bdev_get_dif_type(bdev) != SPDK_DIF_DISABLE) {
3379895d8b56SArtur Paszkiewicz 		SPDK_ERRLOG("Base bdev '%s' has DIF or DIX enabled - unsupported RAID configuration\n",
3380895d8b56SArtur Paszkiewicz 			    bdev->name);
3381895d8b56SArtur Paszkiewicz 		rc = -EINVAL;
3382895d8b56SArtur Paszkiewicz 		goto out;
3383895d8b56SArtur Paszkiewicz 	}
3384895d8b56SArtur Paszkiewicz 
3385895d8b56SArtur Paszkiewicz 	/*
3386895d8b56SArtur Paszkiewicz 	 * Set the raid bdev properties if this is the first base bdev configured,
3387895d8b56SArtur Paszkiewicz 	 * otherwise - verify. Assumption is that all the base bdevs for any raid bdev should
3388895d8b56SArtur Paszkiewicz 	 * have the same blocklen and metadata format.
3389895d8b56SArtur Paszkiewicz 	 */
33901c0f3504SArtur Paszkiewicz 	if (raid_bdev->bdev.blocklen == 0) {
3391895d8b56SArtur Paszkiewicz 		raid_bdev->bdev.blocklen = bdev->blocklen;
3392895d8b56SArtur Paszkiewicz 		raid_bdev->bdev.md_len = spdk_bdev_get_md_size(bdev);
3393895d8b56SArtur Paszkiewicz 		raid_bdev->bdev.md_interleave = spdk_bdev_is_md_interleaved(bdev);
3394192db8deSSlawomir Ptak 		raid_bdev->bdev.dif_type = spdk_bdev_get_dif_type(bdev);
3395192db8deSSlawomir Ptak 		raid_bdev->bdev.dif_check_flags = bdev->dif_check_flags;
3396192db8deSSlawomir Ptak 		raid_bdev->bdev.dif_is_head_of_md = spdk_bdev_is_dif_head_of_md(bdev);
3397fcf59a6fSShuhei Matsumoto 		raid_bdev->bdev.dif_pi_format = bdev->dif_pi_format;
3398895d8b56SArtur Paszkiewicz 	} else {
3399895d8b56SArtur Paszkiewicz 		if (raid_bdev->bdev.blocklen != bdev->blocklen) {
3400895d8b56SArtur Paszkiewicz 			SPDK_ERRLOG("Raid bdev '%s' blocklen %u differs from base bdev '%s' blocklen %u\n",
3401895d8b56SArtur Paszkiewicz 				    raid_bdev->bdev.name, raid_bdev->bdev.blocklen, bdev->name, bdev->blocklen);
3402895d8b56SArtur Paszkiewicz 			rc = -EINVAL;
3403895d8b56SArtur Paszkiewicz 			goto out;
3404895d8b56SArtur Paszkiewicz 		}
3405895d8b56SArtur Paszkiewicz 
3406895d8b56SArtur Paszkiewicz 		if (raid_bdev->bdev.md_len != spdk_bdev_get_md_size(bdev) ||
3407192db8deSSlawomir Ptak 		    raid_bdev->bdev.md_interleave != spdk_bdev_is_md_interleaved(bdev) ||
3408192db8deSSlawomir Ptak 		    raid_bdev->bdev.dif_type != spdk_bdev_get_dif_type(bdev) ||
3409192db8deSSlawomir Ptak 		    raid_bdev->bdev.dif_check_flags != bdev->dif_check_flags ||
3410fcf59a6fSShuhei Matsumoto 		    raid_bdev->bdev.dif_is_head_of_md != spdk_bdev_is_dif_head_of_md(bdev) ||
3411fcf59a6fSShuhei Matsumoto 		    raid_bdev->bdev.dif_pi_format != bdev->dif_pi_format) {
3412895d8b56SArtur Paszkiewicz 			SPDK_ERRLOG("Raid bdev '%s' has different metadata format than base bdev '%s'\n",
3413895d8b56SArtur Paszkiewicz 				    raid_bdev->bdev.name, bdev->name);
3414895d8b56SArtur Paszkiewicz 			rc = -EINVAL;
3415895d8b56SArtur Paszkiewicz 			goto out;
3416895d8b56SArtur Paszkiewicz 		}
3417895d8b56SArtur Paszkiewicz 	}
3418895d8b56SArtur Paszkiewicz 
3419fc2398dfSArtur Paszkiewicz 	assert(base_info->configure_cb == NULL);
3420887b8ec4SArtur Paszkiewicz 	base_info->configure_cb = cb_fn;
3421887b8ec4SArtur Paszkiewicz 	base_info->configure_cb_ctx = cb_ctx;
3422887b8ec4SArtur Paszkiewicz 
34239222ff97SArtur Paszkiewicz 	if (existing) {
34249222ff97SArtur Paszkiewicz 		raid_bdev_configure_base_bdev_cont(base_info);
34259222ff97SArtur Paszkiewicz 	} else {
34269222ff97SArtur Paszkiewicz 		/* check for existing superblock when using a new bdev */
34279222ff97SArtur Paszkiewicz 		rc = raid_bdev_load_base_bdev_superblock(desc, base_info->app_thread_ch,
34289222ff97SArtur Paszkiewicz 				raid_bdev_configure_base_bdev_check_sb_cb, base_info);
34299222ff97SArtur Paszkiewicz 		if (rc) {
34309222ff97SArtur Paszkiewicz 			SPDK_ERRLOG("Failed to read bdev %s superblock: %s\n",
34319222ff97SArtur Paszkiewicz 				    bdev->name, spdk_strerror(-rc));
34328a6bb6a8SArtur Paszkiewicz 		}
34338a6bb6a8SArtur Paszkiewicz 	}
34348a6bb6a8SArtur Paszkiewicz out:
34358a6bb6a8SArtur Paszkiewicz 	if (rc != 0) {
3436fc2398dfSArtur Paszkiewicz 		base_info->configure_cb = NULL;
34378a6bb6a8SArtur Paszkiewicz 		raid_bdev_free_base_bdev_resource(base_info);
34388a6bb6a8SArtur Paszkiewicz 	}
343907fe6a43SSeth Howell 	return rc;
344007fe6a43SSeth Howell }
344107fe6a43SSeth Howell 
3442887b8ec4SArtur Paszkiewicz int
3443e9af23deSArtur Paszkiewicz raid_bdev_add_base_bdev(struct raid_bdev *raid_bdev, const char *name,
3444887b8ec4SArtur Paszkiewicz 			raid_base_bdev_cb cb_fn, void *cb_ctx)
3445887b8ec4SArtur Paszkiewicz {
3446887b8ec4SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info = NULL, *iter;
3447887b8ec4SArtur Paszkiewicz 	int rc;
3448887b8ec4SArtur Paszkiewicz 
3449e9af23deSArtur Paszkiewicz 	assert(name != NULL);
3450887b8ec4SArtur Paszkiewicz 	assert(spdk_get_thread() == spdk_thread_get_app_thread());
3451887b8ec4SArtur Paszkiewicz 
3452574d258eSYankun Li 	if (raid_bdev->process != NULL) {
3453574d258eSYankun Li 		SPDK_ERRLOG("raid bdev '%s' is in process\n",
3454574d258eSYankun Li 			    raid_bdev->bdev.name);
3455574d258eSYankun Li 		return -EPERM;
3456574d258eSYankun Li 	}
3457574d258eSYankun Li 
34582a1b861bSArtur Paszkiewicz 	if (raid_bdev->state == RAID_BDEV_STATE_CONFIGURING) {
34592a1b861bSArtur Paszkiewicz 		struct spdk_bdev *bdev = spdk_bdev_get_by_name(name);
34602a1b861bSArtur Paszkiewicz 
34612a1b861bSArtur Paszkiewicz 		if (bdev != NULL) {
3462887b8ec4SArtur Paszkiewicz 			RAID_FOR_EACH_BASE_BDEV(raid_bdev, iter) {
34632a1b861bSArtur Paszkiewicz 				if (iter->name == NULL &&
34642a1b861bSArtur Paszkiewicz 				    spdk_uuid_compare(&bdev->uuid, &iter->uuid) == 0) {
3465887b8ec4SArtur Paszkiewicz 					base_info = iter;
3466887b8ec4SArtur Paszkiewicz 					break;
3467887b8ec4SArtur Paszkiewicz 				}
3468887b8ec4SArtur Paszkiewicz 			}
34692a1b861bSArtur Paszkiewicz 		}
34702a1b861bSArtur Paszkiewicz 	}
34712a1b861bSArtur Paszkiewicz 
34722a1b861bSArtur Paszkiewicz 	if (base_info == NULL || raid_bdev->state == RAID_BDEV_STATE_ONLINE) {
34732a1b861bSArtur Paszkiewicz 		RAID_FOR_EACH_BASE_BDEV(raid_bdev, iter) {
34742a1b861bSArtur Paszkiewicz 			if (iter->name == NULL && spdk_uuid_is_null(&iter->uuid)) {
34752a1b861bSArtur Paszkiewicz 				base_info = iter;
34762a1b861bSArtur Paszkiewicz 				break;
34772a1b861bSArtur Paszkiewicz 			}
34782a1b861bSArtur Paszkiewicz 		}
34792a1b861bSArtur Paszkiewicz 	}
3480887b8ec4SArtur Paszkiewicz 
3481887b8ec4SArtur Paszkiewicz 	if (base_info == NULL) {
3482887b8ec4SArtur Paszkiewicz 		SPDK_ERRLOG("no empty slot found in raid bdev '%s' for new base bdev '%s'\n",
3483210c233fSArtur Paszkiewicz 			    raid_bdev->bdev.name, name);
3484887b8ec4SArtur Paszkiewicz 		return -EINVAL;
3485887b8ec4SArtur Paszkiewicz 	}
3486887b8ec4SArtur Paszkiewicz 
3487887b8ec4SArtur Paszkiewicz 	assert(base_info->is_configured == false);
34880074299dSArtur Paszkiewicz 
34890074299dSArtur Paszkiewicz 	if (raid_bdev->state == RAID_BDEV_STATE_ONLINE) {
3490887b8ec4SArtur Paszkiewicz 		assert(base_info->data_size != 0);
34910074299dSArtur Paszkiewicz 		assert(base_info->desc == NULL);
34920074299dSArtur Paszkiewicz 	}
3493887b8ec4SArtur Paszkiewicz 
3494e9af23deSArtur Paszkiewicz 	base_info->name = strdup(name);
3495e9af23deSArtur Paszkiewicz 	if (base_info->name == NULL) {
3496e9af23deSArtur Paszkiewicz 		return -ENOMEM;
3497e9af23deSArtur Paszkiewicz 	}
3498e9af23deSArtur Paszkiewicz 
3499e9af23deSArtur Paszkiewicz 	rc = raid_bdev_configure_base_bdev(base_info, false, cb_fn, cb_ctx);
35000074299dSArtur Paszkiewicz 	if (rc != 0 && (rc != -ENODEV || raid_bdev->state != RAID_BDEV_STATE_CONFIGURING)) {
3501e9af23deSArtur Paszkiewicz 		SPDK_ERRLOG("base bdev '%s' configure failed: %s\n", name, spdk_strerror(-rc));
3502e9af23deSArtur Paszkiewicz 		free(base_info->name);
3503e9af23deSArtur Paszkiewicz 		base_info->name = NULL;
3504887b8ec4SArtur Paszkiewicz 	}
3505887b8ec4SArtur Paszkiewicz 
350607fe6a43SSeth Howell 	return rc;
350707fe6a43SSeth Howell }
350807fe6a43SSeth Howell 
35098a6bb6a8SArtur Paszkiewicz static int
35108a6bb6a8SArtur Paszkiewicz raid_bdev_create_from_sb(const struct raid_bdev_superblock *sb, struct raid_bdev **raid_bdev_out)
35118a6bb6a8SArtur Paszkiewicz {
35128a6bb6a8SArtur Paszkiewicz 	struct raid_bdev *raid_bdev;
35138a6bb6a8SArtur Paszkiewicz 	uint8_t i;
35148a6bb6a8SArtur Paszkiewicz 	int rc;
35158a6bb6a8SArtur Paszkiewicz 
3516255d0786SArtur Paszkiewicz 	rc = _raid_bdev_create(sb->name, (sb->strip_size * sb->block_size) / 1024, sb->num_base_bdevs,
35178a6bb6a8SArtur Paszkiewicz 			       sb->level, true, &sb->uuid, &raid_bdev);
35188a6bb6a8SArtur Paszkiewicz 	if (rc != 0) {
35198a6bb6a8SArtur Paszkiewicz 		return rc;
35208a6bb6a8SArtur Paszkiewicz 	}
35218a6bb6a8SArtur Paszkiewicz 
3522c25b80e2SArtur Paszkiewicz 	rc = raid_bdev_alloc_superblock(raid_bdev, sb->block_size);
3523c25b80e2SArtur Paszkiewicz 	if (rc != 0) {
3524c25b80e2SArtur Paszkiewicz 		raid_bdev_free(raid_bdev);
3525c25b80e2SArtur Paszkiewicz 		return rc;
3526c25b80e2SArtur Paszkiewicz 	}
3527c25b80e2SArtur Paszkiewicz 
35288a6bb6a8SArtur Paszkiewicz 	assert(sb->length <= RAID_BDEV_SB_MAX_LENGTH);
35298a6bb6a8SArtur Paszkiewicz 	memcpy(raid_bdev->sb, sb, sb->length);
35308a6bb6a8SArtur Paszkiewicz 
35318a6bb6a8SArtur Paszkiewicz 	for (i = 0; i < sb->base_bdevs_size; i++) {
35328a6bb6a8SArtur Paszkiewicz 		const struct raid_bdev_sb_base_bdev *sb_base_bdev = &sb->base_bdevs[i];
35338a6bb6a8SArtur Paszkiewicz 		struct raid_base_bdev_info *base_info = &raid_bdev->base_bdev_info[sb_base_bdev->slot];
35348a6bb6a8SArtur Paszkiewicz 
35358a6bb6a8SArtur Paszkiewicz 		if (sb_base_bdev->state == RAID_SB_BASE_BDEV_CONFIGURED) {
35368a6bb6a8SArtur Paszkiewicz 			spdk_uuid_copy(&base_info->uuid, &sb_base_bdev->uuid);
3537255d0786SArtur Paszkiewicz 			raid_bdev->num_base_bdevs_operational++;
35388a6bb6a8SArtur Paszkiewicz 		}
35398a6bb6a8SArtur Paszkiewicz 
35408a6bb6a8SArtur Paszkiewicz 		base_info->data_offset = sb_base_bdev->data_offset;
35418a6bb6a8SArtur Paszkiewicz 		base_info->data_size = sb_base_bdev->data_size;
35428a6bb6a8SArtur Paszkiewicz 	}
35438a6bb6a8SArtur Paszkiewicz 
35448a6bb6a8SArtur Paszkiewicz 	*raid_bdev_out = raid_bdev;
35458a6bb6a8SArtur Paszkiewicz 	return 0;
35468a6bb6a8SArtur Paszkiewicz }
35478a6bb6a8SArtur Paszkiewicz 
35488a6bb6a8SArtur Paszkiewicz static void
35498a6bb6a8SArtur Paszkiewicz raid_bdev_examine_no_sb(struct spdk_bdev *bdev)
35508a6bb6a8SArtur Paszkiewicz {
35518a6bb6a8SArtur Paszkiewicz 	struct raid_bdev *raid_bdev;
35528a6bb6a8SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info;
35538a6bb6a8SArtur Paszkiewicz 
35548a6bb6a8SArtur Paszkiewicz 	TAILQ_FOREACH(raid_bdev, &g_raid_bdev_list, global_link) {
35558aa7730cSArtur Paszkiewicz 		if (raid_bdev->state != RAID_BDEV_STATE_CONFIGURING || raid_bdev->sb != NULL) {
35568aa7730cSArtur Paszkiewicz 			continue;
35578aa7730cSArtur Paszkiewicz 		}
35588a6bb6a8SArtur Paszkiewicz 		RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
35592a1b861bSArtur Paszkiewicz 			if (base_info->desc == NULL &&
35602a1b861bSArtur Paszkiewicz 			    ((base_info->name != NULL && strcmp(bdev->name, base_info->name) == 0) ||
35612a1b861bSArtur Paszkiewicz 			     spdk_uuid_compare(&base_info->uuid, &bdev->uuid) == 0)) {
3562887b8ec4SArtur Paszkiewicz 				raid_bdev_configure_base_bdev(base_info, true, NULL, NULL);
35638a6bb6a8SArtur Paszkiewicz 				break;
35648a6bb6a8SArtur Paszkiewicz 			}
35658a6bb6a8SArtur Paszkiewicz 		}
35668a6bb6a8SArtur Paszkiewicz 	}
35678a6bb6a8SArtur Paszkiewicz }
35688a6bb6a8SArtur Paszkiewicz 
3569f9cccaa8SArtur Paszkiewicz struct raid_bdev_examine_others_ctx {
3570f9cccaa8SArtur Paszkiewicz 	struct spdk_uuid raid_bdev_uuid;
3571f9cccaa8SArtur Paszkiewicz 	uint8_t current_base_bdev_idx;
3572f9cccaa8SArtur Paszkiewicz 	raid_base_bdev_cb cb_fn;
3573f9cccaa8SArtur Paszkiewicz 	void *cb_ctx;
3574f9cccaa8SArtur Paszkiewicz };
3575f9cccaa8SArtur Paszkiewicz 
3576f9cccaa8SArtur Paszkiewicz static void
3577f9cccaa8SArtur Paszkiewicz raid_bdev_examine_others_done(void *_ctx, int status)
3578f9cccaa8SArtur Paszkiewicz {
3579f9cccaa8SArtur Paszkiewicz 	struct raid_bdev_examine_others_ctx *ctx = _ctx;
3580f9cccaa8SArtur Paszkiewicz 
3581f9cccaa8SArtur Paszkiewicz 	if (ctx->cb_fn != NULL) {
3582f9cccaa8SArtur Paszkiewicz 		ctx->cb_fn(ctx->cb_ctx, status);
3583f9cccaa8SArtur Paszkiewicz 	}
3584f9cccaa8SArtur Paszkiewicz 	free(ctx);
3585f9cccaa8SArtur Paszkiewicz }
3586f9cccaa8SArtur Paszkiewicz 
3587f9cccaa8SArtur Paszkiewicz typedef void (*raid_bdev_examine_load_sb_cb)(struct spdk_bdev *bdev,
3588f9cccaa8SArtur Paszkiewicz 		const struct raid_bdev_superblock *sb, int status, void *ctx);
3589f9cccaa8SArtur Paszkiewicz static int raid_bdev_examine_load_sb(const char *bdev_name, raid_bdev_examine_load_sb_cb cb,
3590f9cccaa8SArtur Paszkiewicz 				     void *cb_ctx);
3591f9cccaa8SArtur Paszkiewicz static void raid_bdev_examine_sb(const struct raid_bdev_superblock *sb, struct spdk_bdev *bdev,
3592f9cccaa8SArtur Paszkiewicz 				 raid_base_bdev_cb cb_fn, void *cb_ctx);
3593f9cccaa8SArtur Paszkiewicz static void raid_bdev_examine_others(void *_ctx, int status);
3594f9cccaa8SArtur Paszkiewicz 
3595f9cccaa8SArtur Paszkiewicz static void
3596f9cccaa8SArtur Paszkiewicz raid_bdev_examine_others_load_cb(struct spdk_bdev *bdev, const struct raid_bdev_superblock *sb,
3597f9cccaa8SArtur Paszkiewicz 				 int status, void *_ctx)
3598f9cccaa8SArtur Paszkiewicz {
3599f9cccaa8SArtur Paszkiewicz 	struct raid_bdev_examine_others_ctx *ctx = _ctx;
3600f9cccaa8SArtur Paszkiewicz 
3601f9cccaa8SArtur Paszkiewicz 	if (status != 0) {
3602f9cccaa8SArtur Paszkiewicz 		raid_bdev_examine_others_done(ctx, status);
3603f9cccaa8SArtur Paszkiewicz 		return;
3604f9cccaa8SArtur Paszkiewicz 	}
3605f9cccaa8SArtur Paszkiewicz 
3606f9cccaa8SArtur Paszkiewicz 	raid_bdev_examine_sb(sb, bdev, raid_bdev_examine_others, ctx);
3607f9cccaa8SArtur Paszkiewicz }
3608f9cccaa8SArtur Paszkiewicz 
3609f9cccaa8SArtur Paszkiewicz static void
3610f9cccaa8SArtur Paszkiewicz raid_bdev_examine_others(void *_ctx, int status)
3611f9cccaa8SArtur Paszkiewicz {
3612f9cccaa8SArtur Paszkiewicz 	struct raid_bdev_examine_others_ctx *ctx = _ctx;
3613f9cccaa8SArtur Paszkiewicz 	struct raid_bdev *raid_bdev;
3614f9cccaa8SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info;
3615f9cccaa8SArtur Paszkiewicz 	char uuid_str[SPDK_UUID_STRING_LEN];
3616f9cccaa8SArtur Paszkiewicz 
361719f5787cSArtur Paszkiewicz 	if (status != 0 && status != -EEXIST) {
3618f9cccaa8SArtur Paszkiewicz 		goto out;
3619f9cccaa8SArtur Paszkiewicz 	}
3620f9cccaa8SArtur Paszkiewicz 
3621f9cccaa8SArtur Paszkiewicz 	raid_bdev = raid_bdev_find_by_uuid(&ctx->raid_bdev_uuid);
3622f9cccaa8SArtur Paszkiewicz 	if (raid_bdev == NULL) {
3623f9cccaa8SArtur Paszkiewicz 		status = -ENODEV;
3624f9cccaa8SArtur Paszkiewicz 		goto out;
3625f9cccaa8SArtur Paszkiewicz 	}
3626f9cccaa8SArtur Paszkiewicz 
3627f9cccaa8SArtur Paszkiewicz 	for (base_info = &raid_bdev->base_bdev_info[ctx->current_base_bdev_idx];
3628f9cccaa8SArtur Paszkiewicz 	     base_info < &raid_bdev->base_bdev_info[raid_bdev->num_base_bdevs];
3629f9cccaa8SArtur Paszkiewicz 	     base_info++) {
3630f9cccaa8SArtur Paszkiewicz 		if (base_info->is_configured || spdk_uuid_is_null(&base_info->uuid)) {
3631f9cccaa8SArtur Paszkiewicz 			continue;
3632f9cccaa8SArtur Paszkiewicz 		}
3633f9cccaa8SArtur Paszkiewicz 
3634f9cccaa8SArtur Paszkiewicz 		spdk_uuid_fmt_lower(uuid_str, sizeof(uuid_str), &base_info->uuid);
3635f9cccaa8SArtur Paszkiewicz 
3636f9cccaa8SArtur Paszkiewicz 		if (spdk_bdev_get_by_name(uuid_str) == NULL) {
3637f9cccaa8SArtur Paszkiewicz 			continue;
3638f9cccaa8SArtur Paszkiewicz 		}
3639f9cccaa8SArtur Paszkiewicz 
3640f9cccaa8SArtur Paszkiewicz 		ctx->current_base_bdev_idx = raid_bdev_base_bdev_slot(base_info);
3641f9cccaa8SArtur Paszkiewicz 
3642f9cccaa8SArtur Paszkiewicz 		status = raid_bdev_examine_load_sb(uuid_str, raid_bdev_examine_others_load_cb, ctx);
3643f9cccaa8SArtur Paszkiewicz 		if (status != 0) {
3644f9cccaa8SArtur Paszkiewicz 			continue;
3645f9cccaa8SArtur Paszkiewicz 		}
3646f9cccaa8SArtur Paszkiewicz 		return;
3647f9cccaa8SArtur Paszkiewicz 	}
3648f9cccaa8SArtur Paszkiewicz out:
3649f9cccaa8SArtur Paszkiewicz 	raid_bdev_examine_others_done(ctx, status);
3650f9cccaa8SArtur Paszkiewicz }
3651f9cccaa8SArtur Paszkiewicz 
36528a6bb6a8SArtur Paszkiewicz static void
3653b694ff86SArtur Paszkiewicz raid_bdev_examine_sb(const struct raid_bdev_superblock *sb, struct spdk_bdev *bdev,
3654b694ff86SArtur Paszkiewicz 		     raid_base_bdev_cb cb_fn, void *cb_ctx)
36558a6bb6a8SArtur Paszkiewicz {
36563bec6cb2SMichal Berger 	const struct raid_bdev_sb_base_bdev *sb_base_bdev = NULL;
36578a6bb6a8SArtur Paszkiewicz 	struct raid_bdev *raid_bdev;
36588a6bb6a8SArtur Paszkiewicz 	struct raid_base_bdev_info *iter, *base_info;
36598a6bb6a8SArtur Paszkiewicz 	uint8_t i;
36608a6bb6a8SArtur Paszkiewicz 	int rc;
36618a6bb6a8SArtur Paszkiewicz 
3662bb374988SArtur Paszkiewicz 	if (sb->block_size != spdk_bdev_get_data_block_size(bdev)) {
36638a6bb6a8SArtur Paszkiewicz 		SPDK_WARNLOG("Bdev %s block size (%u) does not match the value in superblock (%u)\n",
3664bb374988SArtur Paszkiewicz 			     bdev->name, sb->block_size, spdk_bdev_get_data_block_size(bdev));
3665b694ff86SArtur Paszkiewicz 		rc = -EINVAL;
3666b694ff86SArtur Paszkiewicz 		goto out;
36678a6bb6a8SArtur Paszkiewicz 	}
36688a6bb6a8SArtur Paszkiewicz 
36698a6bb6a8SArtur Paszkiewicz 	if (spdk_uuid_is_null(&sb->uuid)) {
36708a6bb6a8SArtur Paszkiewicz 		SPDK_WARNLOG("NULL raid bdev UUID in superblock on bdev %s\n", bdev->name);
3671b694ff86SArtur Paszkiewicz 		rc = -EINVAL;
3672b694ff86SArtur Paszkiewicz 		goto out;
36738a6bb6a8SArtur Paszkiewicz 	}
36748a6bb6a8SArtur Paszkiewicz 
3675688de1b9SArtur Paszkiewicz 	raid_bdev = raid_bdev_find_by_uuid(&sb->uuid);
36768a6bb6a8SArtur Paszkiewicz 
36778a6bb6a8SArtur Paszkiewicz 	if (raid_bdev) {
3678*fa3ab738SYankun Li 		if (raid_bdev->sb == NULL) {
3679*fa3ab738SYankun Li 			SPDK_WARNLOG("raid superblock is null\n");
3680*fa3ab738SYankun Li 			rc = -EINVAL;
3681*fa3ab738SYankun Li 			goto out;
3682*fa3ab738SYankun Li 		}
3683*fa3ab738SYankun Li 
36848a6bb6a8SArtur Paszkiewicz 		if (sb->seq_number > raid_bdev->sb->seq_number) {
36858a6bb6a8SArtur Paszkiewicz 			SPDK_DEBUGLOG(bdev_raid,
36868a6bb6a8SArtur Paszkiewicz 				      "raid superblock seq_number on bdev %s (%lu) greater than existing raid bdev %s (%lu)\n",
36878a6bb6a8SArtur Paszkiewicz 				      bdev->name, sb->seq_number, raid_bdev->bdev.name, raid_bdev->sb->seq_number);
36888a6bb6a8SArtur Paszkiewicz 
36898a6bb6a8SArtur Paszkiewicz 			if (raid_bdev->state != RAID_BDEV_STATE_CONFIGURING) {
36908a6bb6a8SArtur Paszkiewicz 				SPDK_WARNLOG("Newer version of raid bdev %s superblock found on bdev %s but raid bdev is not in configuring state.\n",
36918a6bb6a8SArtur Paszkiewicz 					     raid_bdev->bdev.name, bdev->name);
3692b694ff86SArtur Paszkiewicz 				rc = -EBUSY;
3693b694ff86SArtur Paszkiewicz 				goto out;
36948a6bb6a8SArtur Paszkiewicz 			}
36958a6bb6a8SArtur Paszkiewicz 
36968a6bb6a8SArtur Paszkiewicz 			/* remove and then recreate the raid bdev using the newer superblock */
36978a6bb6a8SArtur Paszkiewicz 			raid_bdev_delete(raid_bdev, NULL, NULL);
36988a6bb6a8SArtur Paszkiewicz 			raid_bdev = NULL;
36998a6bb6a8SArtur Paszkiewicz 		} else if (sb->seq_number < raid_bdev->sb->seq_number) {
37008a6bb6a8SArtur Paszkiewicz 			SPDK_DEBUGLOG(bdev_raid,
37018a6bb6a8SArtur Paszkiewicz 				      "raid superblock seq_number on bdev %s (%lu) smaller than existing raid bdev %s (%lu)\n",
37028a6bb6a8SArtur Paszkiewicz 				      bdev->name, sb->seq_number, raid_bdev->bdev.name, raid_bdev->sb->seq_number);
37038a6bb6a8SArtur Paszkiewicz 			/* use the current raid bdev superblock */
37048a6bb6a8SArtur Paszkiewicz 			sb = raid_bdev->sb;
37058a6bb6a8SArtur Paszkiewicz 		}
37068a6bb6a8SArtur Paszkiewicz 	}
37078a6bb6a8SArtur Paszkiewicz 
37088a6bb6a8SArtur Paszkiewicz 	for (i = 0; i < sb->base_bdevs_size; i++) {
37098a6bb6a8SArtur Paszkiewicz 		sb_base_bdev = &sb->base_bdevs[i];
37108a6bb6a8SArtur Paszkiewicz 
37118a6bb6a8SArtur Paszkiewicz 		assert(spdk_uuid_is_null(&sb_base_bdev->uuid) == false);
37128a6bb6a8SArtur Paszkiewicz 
37138a6bb6a8SArtur Paszkiewicz 		if (spdk_uuid_compare(&sb_base_bdev->uuid, spdk_bdev_get_uuid(bdev)) == 0) {
37148a6bb6a8SArtur Paszkiewicz 			break;
37158a6bb6a8SArtur Paszkiewicz 		}
37168a6bb6a8SArtur Paszkiewicz 	}
37178a6bb6a8SArtur Paszkiewicz 
37188a6bb6a8SArtur Paszkiewicz 	if (i == sb->base_bdevs_size) {
37198a6bb6a8SArtur Paszkiewicz 		SPDK_DEBUGLOG(bdev_raid, "raid superblock does not contain this bdev's uuid\n");
3720b694ff86SArtur Paszkiewicz 		rc = -EINVAL;
3721b694ff86SArtur Paszkiewicz 		goto out;
37228a6bb6a8SArtur Paszkiewicz 	}
37238a6bb6a8SArtur Paszkiewicz 
37248a6bb6a8SArtur Paszkiewicz 	if (!raid_bdev) {
3725f9cccaa8SArtur Paszkiewicz 		struct raid_bdev_examine_others_ctx *ctx;
3726f9cccaa8SArtur Paszkiewicz 
3727f9cccaa8SArtur Paszkiewicz 		ctx = calloc(1, sizeof(*ctx));
3728f9cccaa8SArtur Paszkiewicz 		if (ctx == NULL) {
3729f9cccaa8SArtur Paszkiewicz 			rc = -ENOMEM;
3730f9cccaa8SArtur Paszkiewicz 			goto out;
3731f9cccaa8SArtur Paszkiewicz 		}
3732f9cccaa8SArtur Paszkiewicz 
37338a6bb6a8SArtur Paszkiewicz 		rc = raid_bdev_create_from_sb(sb, &raid_bdev);
37348a6bb6a8SArtur Paszkiewicz 		if (rc != 0) {
37358a6bb6a8SArtur Paszkiewicz 			SPDK_ERRLOG("Failed to create raid bdev %s: %s\n",
37368a6bb6a8SArtur Paszkiewicz 				    sb->name, spdk_strerror(-rc));
3737f9cccaa8SArtur Paszkiewicz 			free(ctx);
3738b694ff86SArtur Paszkiewicz 			goto out;
37398a6bb6a8SArtur Paszkiewicz 		}
3740f9cccaa8SArtur Paszkiewicz 
3741f9cccaa8SArtur Paszkiewicz 		/* after this base bdev is configured, examine other base bdevs that may be present */
3742f9cccaa8SArtur Paszkiewicz 		spdk_uuid_copy(&ctx->raid_bdev_uuid, &sb->uuid);
3743f9cccaa8SArtur Paszkiewicz 		ctx->cb_fn = cb_fn;
3744f9cccaa8SArtur Paszkiewicz 		ctx->cb_ctx = cb_ctx;
3745f9cccaa8SArtur Paszkiewicz 
3746f9cccaa8SArtur Paszkiewicz 		cb_fn = raid_bdev_examine_others;
3747f9cccaa8SArtur Paszkiewicz 		cb_ctx = ctx;
37488a6bb6a8SArtur Paszkiewicz 	}
37498a6bb6a8SArtur Paszkiewicz 
3750dafdb289SArtur Paszkiewicz 	if (raid_bdev->state == RAID_BDEV_STATE_ONLINE) {
3751dafdb289SArtur Paszkiewicz 		assert(sb_base_bdev->slot < raid_bdev->num_base_bdevs);
3752dafdb289SArtur Paszkiewicz 		base_info = &raid_bdev->base_bdev_info[sb_base_bdev->slot];
37536518a98dSArtur Paszkiewicz 		assert(base_info->is_configured == false);
3754dafdb289SArtur Paszkiewicz 		assert(sb_base_bdev->state == RAID_SB_BASE_BDEV_MISSING ||
3755dafdb289SArtur Paszkiewicz 		       sb_base_bdev->state == RAID_SB_BASE_BDEV_FAILED);
3756dafdb289SArtur Paszkiewicz 		assert(spdk_uuid_is_null(&base_info->uuid));
3757dafdb289SArtur Paszkiewicz 		spdk_uuid_copy(&base_info->uuid, &sb_base_bdev->uuid);
3758dafdb289SArtur Paszkiewicz 		SPDK_NOTICELOG("Re-adding bdev %s to raid bdev %s.\n", bdev->name, raid_bdev->bdev.name);
3759dafdb289SArtur Paszkiewicz 		rc = raid_bdev_configure_base_bdev(base_info, true, cb_fn, cb_ctx);
3760dafdb289SArtur Paszkiewicz 		if (rc != 0) {
3761dafdb289SArtur Paszkiewicz 			SPDK_ERRLOG("Failed to configure bdev %s as base bdev of raid %s: %s\n",
3762dafdb289SArtur Paszkiewicz 				    bdev->name, raid_bdev->bdev.name, spdk_strerror(-rc));
3763dafdb289SArtur Paszkiewicz 		}
3764dafdb289SArtur Paszkiewicz 		goto out;
3765dafdb289SArtur Paszkiewicz 	}
3766dafdb289SArtur Paszkiewicz 
37678a6bb6a8SArtur Paszkiewicz 	if (sb_base_bdev->state != RAID_SB_BASE_BDEV_CONFIGURED) {
37688a6bb6a8SArtur Paszkiewicz 		SPDK_NOTICELOG("Bdev %s is not an active member of raid bdev %s. Ignoring.\n",
37698a6bb6a8SArtur Paszkiewicz 			       bdev->name, raid_bdev->bdev.name);
3770b694ff86SArtur Paszkiewicz 		rc = -EINVAL;
3771b694ff86SArtur Paszkiewicz 		goto out;
37728a6bb6a8SArtur Paszkiewicz 	}
37738a6bb6a8SArtur Paszkiewicz 
37748a6bb6a8SArtur Paszkiewicz 	base_info = NULL;
37758a6bb6a8SArtur Paszkiewicz 	RAID_FOR_EACH_BASE_BDEV(raid_bdev, iter) {
37768a6bb6a8SArtur Paszkiewicz 		if (spdk_uuid_compare(&iter->uuid, spdk_bdev_get_uuid(bdev)) == 0) {
37778a6bb6a8SArtur Paszkiewicz 			base_info = iter;
37788a6bb6a8SArtur Paszkiewicz 			break;
37798a6bb6a8SArtur Paszkiewicz 		}
37808a6bb6a8SArtur Paszkiewicz 	}
37818a6bb6a8SArtur Paszkiewicz 
37828a6bb6a8SArtur Paszkiewicz 	if (base_info == NULL) {
37838a6bb6a8SArtur Paszkiewicz 		SPDK_ERRLOG("Bdev %s is not a member of raid bdev %s\n",
37848a6bb6a8SArtur Paszkiewicz 			    bdev->name, raid_bdev->bdev.name);
3785b694ff86SArtur Paszkiewicz 		rc = -EINVAL;
3786b694ff86SArtur Paszkiewicz 		goto out;
37878a6bb6a8SArtur Paszkiewicz 	}
37888a6bb6a8SArtur Paszkiewicz 
378919f5787cSArtur Paszkiewicz 	if (base_info->is_configured) {
379019f5787cSArtur Paszkiewicz 		rc = -EEXIST;
379119f5787cSArtur Paszkiewicz 		goto out;
379219f5787cSArtur Paszkiewicz 	}
379319f5787cSArtur Paszkiewicz 
3794b694ff86SArtur Paszkiewicz 	rc = raid_bdev_configure_base_bdev(base_info, true, cb_fn, cb_ctx);
37958a6bb6a8SArtur Paszkiewicz 	if (rc != 0) {
37968a6bb6a8SArtur Paszkiewicz 		SPDK_ERRLOG("Failed to configure bdev %s as base bdev of raid %s: %s\n",
37978a6bb6a8SArtur Paszkiewicz 			    bdev->name, raid_bdev->bdev.name, spdk_strerror(-rc));
37988a6bb6a8SArtur Paszkiewicz 	}
3799b694ff86SArtur Paszkiewicz out:
3800b694ff86SArtur Paszkiewicz 	if (rc != 0 && cb_fn != 0) {
3801b694ff86SArtur Paszkiewicz 		cb_fn(cb_ctx, rc);
3802b694ff86SArtur Paszkiewicz 	}
38038a6bb6a8SArtur Paszkiewicz }
38048a6bb6a8SArtur Paszkiewicz 
38058a6bb6a8SArtur Paszkiewicz struct raid_bdev_examine_ctx {
38068a6bb6a8SArtur Paszkiewicz 	struct spdk_bdev_desc *desc;
38078a6bb6a8SArtur Paszkiewicz 	struct spdk_io_channel *ch;
3808d014bf93SArtur Paszkiewicz 	raid_bdev_examine_load_sb_cb cb;
3809d014bf93SArtur Paszkiewicz 	void *cb_ctx;
38108a6bb6a8SArtur Paszkiewicz };
38118a6bb6a8SArtur Paszkiewicz 
38128a6bb6a8SArtur Paszkiewicz static void
38138a6bb6a8SArtur Paszkiewicz raid_bdev_examine_ctx_free(struct raid_bdev_examine_ctx *ctx)
38148a6bb6a8SArtur Paszkiewicz {
38158a6bb6a8SArtur Paszkiewicz 	if (!ctx) {
38168a6bb6a8SArtur Paszkiewicz 		return;
38178a6bb6a8SArtur Paszkiewicz 	}
38188a6bb6a8SArtur Paszkiewicz 
38198a6bb6a8SArtur Paszkiewicz 	if (ctx->ch) {
38208a6bb6a8SArtur Paszkiewicz 		spdk_put_io_channel(ctx->ch);
38218a6bb6a8SArtur Paszkiewicz 	}
38228a6bb6a8SArtur Paszkiewicz 
38238a6bb6a8SArtur Paszkiewicz 	if (ctx->desc) {
38248a6bb6a8SArtur Paszkiewicz 		spdk_bdev_close(ctx->desc);
38258a6bb6a8SArtur Paszkiewicz 	}
38268a6bb6a8SArtur Paszkiewicz 
38278a6bb6a8SArtur Paszkiewicz 	free(ctx);
38288a6bb6a8SArtur Paszkiewicz }
38298a6bb6a8SArtur Paszkiewicz 
38308a6bb6a8SArtur Paszkiewicz static void
3831d014bf93SArtur Paszkiewicz raid_bdev_examine_load_sb_done(const struct raid_bdev_superblock *sb, int status, void *_ctx)
38328a6bb6a8SArtur Paszkiewicz {
38338a6bb6a8SArtur Paszkiewicz 	struct raid_bdev_examine_ctx *ctx = _ctx;
38348a6bb6a8SArtur Paszkiewicz 	struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(ctx->desc);
38358a6bb6a8SArtur Paszkiewicz 
3836d014bf93SArtur Paszkiewicz 	ctx->cb(bdev, sb, status, ctx->cb_ctx);
3837d014bf93SArtur Paszkiewicz 
3838d014bf93SArtur Paszkiewicz 	raid_bdev_examine_ctx_free(ctx);
3839d014bf93SArtur Paszkiewicz }
3840d014bf93SArtur Paszkiewicz 
3841d014bf93SArtur Paszkiewicz static void
3842d014bf93SArtur Paszkiewicz raid_bdev_examine_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *event_ctx)
3843d014bf93SArtur Paszkiewicz {
3844d014bf93SArtur Paszkiewicz }
3845d014bf93SArtur Paszkiewicz 
3846d014bf93SArtur Paszkiewicz static int
3847d014bf93SArtur Paszkiewicz raid_bdev_examine_load_sb(const char *bdev_name, raid_bdev_examine_load_sb_cb cb, void *cb_ctx)
3848d014bf93SArtur Paszkiewicz {
3849d014bf93SArtur Paszkiewicz 	struct raid_bdev_examine_ctx *ctx;
3850d014bf93SArtur Paszkiewicz 	int rc;
3851d014bf93SArtur Paszkiewicz 
3852d014bf93SArtur Paszkiewicz 	assert(cb != NULL);
3853d014bf93SArtur Paszkiewicz 
3854d014bf93SArtur Paszkiewicz 	ctx = calloc(1, sizeof(*ctx));
3855d014bf93SArtur Paszkiewicz 	if (!ctx) {
3856d014bf93SArtur Paszkiewicz 		return -ENOMEM;
3857d014bf93SArtur Paszkiewicz 	}
3858d014bf93SArtur Paszkiewicz 
3859d014bf93SArtur Paszkiewicz 	rc = spdk_bdev_open_ext(bdev_name, false, raid_bdev_examine_event_cb, NULL, &ctx->desc);
3860d014bf93SArtur Paszkiewicz 	if (rc) {
3861d014bf93SArtur Paszkiewicz 		SPDK_ERRLOG("Failed to open bdev %s: %s\n", bdev_name, spdk_strerror(-rc));
3862d014bf93SArtur Paszkiewicz 		goto err;
3863d014bf93SArtur Paszkiewicz 	}
3864d014bf93SArtur Paszkiewicz 
3865d014bf93SArtur Paszkiewicz 	ctx->ch = spdk_bdev_get_io_channel(ctx->desc);
3866d014bf93SArtur Paszkiewicz 	if (!ctx->ch) {
3867d014bf93SArtur Paszkiewicz 		SPDK_ERRLOG("Failed to get io channel for bdev %s\n", bdev_name);
3868d014bf93SArtur Paszkiewicz 		rc = -ENOMEM;
3869d014bf93SArtur Paszkiewicz 		goto err;
3870d014bf93SArtur Paszkiewicz 	}
3871d014bf93SArtur Paszkiewicz 
3872d014bf93SArtur Paszkiewicz 	ctx->cb = cb;
3873d014bf93SArtur Paszkiewicz 	ctx->cb_ctx = cb_ctx;
3874d014bf93SArtur Paszkiewicz 
3875d014bf93SArtur Paszkiewicz 	rc = raid_bdev_load_base_bdev_superblock(ctx->desc, ctx->ch, raid_bdev_examine_load_sb_done, ctx);
3876d014bf93SArtur Paszkiewicz 	if (rc) {
3877d014bf93SArtur Paszkiewicz 		SPDK_ERRLOG("Failed to read bdev %s superblock: %s\n",
3878d014bf93SArtur Paszkiewicz 			    bdev_name, spdk_strerror(-rc));
3879d014bf93SArtur Paszkiewicz 		goto err;
3880d014bf93SArtur Paszkiewicz 	}
3881d014bf93SArtur Paszkiewicz 
3882d014bf93SArtur Paszkiewicz 	return 0;
3883d014bf93SArtur Paszkiewicz err:
3884d014bf93SArtur Paszkiewicz 	raid_bdev_examine_ctx_free(ctx);
3885d014bf93SArtur Paszkiewicz 	return rc;
3886d014bf93SArtur Paszkiewicz }
3887d014bf93SArtur Paszkiewicz 
3888d014bf93SArtur Paszkiewicz static void
3889bbccfa09SArtur Paszkiewicz raid_bdev_examine_done(void *ctx, int status)
3890bbccfa09SArtur Paszkiewicz {
3891bbccfa09SArtur Paszkiewicz 	struct spdk_bdev *bdev = ctx;
3892bbccfa09SArtur Paszkiewicz 
3893bbccfa09SArtur Paszkiewicz 	if (status != 0) {
3894bbccfa09SArtur Paszkiewicz 		SPDK_ERRLOG("Failed to examine bdev %s: %s\n",
3895bbccfa09SArtur Paszkiewicz 			    bdev->name, spdk_strerror(-status));
3896bbccfa09SArtur Paszkiewicz 	}
3897bbccfa09SArtur Paszkiewicz 	spdk_bdev_module_examine_done(&g_raid_if);
3898bbccfa09SArtur Paszkiewicz }
3899bbccfa09SArtur Paszkiewicz 
3900bbccfa09SArtur Paszkiewicz static void
3901d014bf93SArtur Paszkiewicz raid_bdev_examine_cont(struct spdk_bdev *bdev, const struct raid_bdev_superblock *sb, int status,
3902d014bf93SArtur Paszkiewicz 		       void *ctx)
3903d014bf93SArtur Paszkiewicz {
39048a6bb6a8SArtur Paszkiewicz 	switch (status) {
39058a6bb6a8SArtur Paszkiewicz 	case 0:
39068a6bb6a8SArtur Paszkiewicz 		/* valid superblock found */
39078a6bb6a8SArtur Paszkiewicz 		SPDK_DEBUGLOG(bdev_raid, "raid superblock found on bdev %s\n", bdev->name);
3908a5cd4a6dSArtur Paszkiewicz 		raid_bdev_examine_sb(sb, bdev, raid_bdev_examine_done, bdev);
3909a5cd4a6dSArtur Paszkiewicz 		return;
39108a6bb6a8SArtur Paszkiewicz 	case -EINVAL:
39118a6bb6a8SArtur Paszkiewicz 		/* no valid superblock, check if it can be claimed anyway */
39128a6bb6a8SArtur Paszkiewicz 		raid_bdev_examine_no_sb(bdev);
3913bbccfa09SArtur Paszkiewicz 		status = 0;
39148a6bb6a8SArtur Paszkiewicz 		break;
39158a6bb6a8SArtur Paszkiewicz 	}
39168a6bb6a8SArtur Paszkiewicz 
3917bbccfa09SArtur Paszkiewicz 	raid_bdev_examine_done(bdev, status);
39188a6bb6a8SArtur Paszkiewicz }
39198a6bb6a8SArtur Paszkiewicz 
392007fe6a43SSeth Howell /*
392107fe6a43SSeth Howell  * brief:
392207fe6a43SSeth Howell  * raid_bdev_examine function is the examine function call by the below layers
392307fe6a43SSeth Howell  * like bdev_nvme layer. This function will check if this base bdev can be
392407fe6a43SSeth Howell  * claimed by this raid bdev or not.
392507fe6a43SSeth Howell  * params:
392607fe6a43SSeth Howell  * bdev - pointer to base bdev
392707fe6a43SSeth Howell  * returns:
392807fe6a43SSeth Howell  * none
392907fe6a43SSeth Howell  */
393007fe6a43SSeth Howell static void
393107fe6a43SSeth Howell raid_bdev_examine(struct spdk_bdev *bdev)
393207fe6a43SSeth Howell {
3933bbccfa09SArtur Paszkiewicz 	int rc = 0;
393407fe6a43SSeth Howell 
3935ef282937SArtur Paszkiewicz 	if (raid_bdev_find_base_info_by_bdev(bdev) != NULL) {
3936ef282937SArtur Paszkiewicz 		goto done;
3937ef282937SArtur Paszkiewicz 	}
3938ef282937SArtur Paszkiewicz 
3939796c1391SArtur Paszkiewicz 	if (spdk_bdev_get_dif_type(bdev) != SPDK_DIF_DISABLE) {
3940796c1391SArtur Paszkiewicz 		raid_bdev_examine_no_sb(bdev);
3941ef282937SArtur Paszkiewicz 		goto done;
3942796c1391SArtur Paszkiewicz 	}
3943796c1391SArtur Paszkiewicz 
3944d014bf93SArtur Paszkiewicz 	rc = raid_bdev_examine_load_sb(bdev->name, raid_bdev_examine_cont, NULL);
3945d014bf93SArtur Paszkiewicz 	if (rc != 0) {
3946d014bf93SArtur Paszkiewicz 		goto done;
39478a6bb6a8SArtur Paszkiewicz 	}
39488a6bb6a8SArtur Paszkiewicz 
39498a6bb6a8SArtur Paszkiewicz 	return;
3950ef282937SArtur Paszkiewicz done:
3951bbccfa09SArtur Paszkiewicz 	raid_bdev_examine_done(bdev, rc);
395207fe6a43SSeth Howell }
395307fe6a43SSeth Howell 
395407fe6a43SSeth Howell /* Log component for bdev raid bdev module */
39552172c432STomasz Zawadzki SPDK_LOG_REGISTER_COMPONENT(bdev_raid)
39568d52c4c2Sxupeng-mingtu 
3957fbfc2c9dSKonrad Sztyber static void
3958fbfc2c9dSKonrad Sztyber bdev_raid_trace(void)
39598d52c4c2Sxupeng-mingtu {
39608d52c4c2Sxupeng-mingtu 	struct spdk_trace_tpoint_opts opts[] = {
39618d52c4c2Sxupeng-mingtu 		{
39628d52c4c2Sxupeng-mingtu 			"BDEV_RAID_IO_START", TRACE_BDEV_RAID_IO_START,
39638d52c4c2Sxupeng-mingtu 			OWNER_TYPE_NONE, OBJECT_BDEV_RAID_IO, 1,
39648d52c4c2Sxupeng-mingtu 			{{ "ctx", SPDK_TRACE_ARG_TYPE_PTR, 8 }}
39658d52c4c2Sxupeng-mingtu 		},
39668d52c4c2Sxupeng-mingtu 		{
39678d52c4c2Sxupeng-mingtu 			"BDEV_RAID_IO_DONE", TRACE_BDEV_RAID_IO_DONE,
39688d52c4c2Sxupeng-mingtu 			OWNER_TYPE_NONE, OBJECT_BDEV_RAID_IO, 0,
39698d52c4c2Sxupeng-mingtu 			{{ "ctx", SPDK_TRACE_ARG_TYPE_PTR, 8 }}
39708d52c4c2Sxupeng-mingtu 		}
39718d52c4c2Sxupeng-mingtu 	};
39728d52c4c2Sxupeng-mingtu 
39738d52c4c2Sxupeng-mingtu 
39748d52c4c2Sxupeng-mingtu 	spdk_trace_register_object(OBJECT_BDEV_RAID_IO, 'R');
39758d52c4c2Sxupeng-mingtu 	spdk_trace_register_description_ext(opts, SPDK_COUNTOF(opts));
39768d52c4c2Sxupeng-mingtu 	spdk_trace_tpoint_register_relation(TRACE_BDEV_IO_START, OBJECT_BDEV_RAID_IO, 1);
39778d52c4c2Sxupeng-mingtu 	spdk_trace_tpoint_register_relation(TRACE_BDEV_IO_DONE, OBJECT_BDEV_RAID_IO, 0);
39788d52c4c2Sxupeng-mingtu }
3979fbfc2c9dSKonrad Sztyber SPDK_TRACE_REGISTER_FN(bdev_raid_trace, "bdev_raid", TRACE_GROUP_BDEV_RAID)
3980