xref: /spdk/module/bdev/raid/raid1.c (revision 3b9baa5f8af96f31278fc8f7e34f2ab7444787f7)
1208f21cdSKrzysztof Smolinski /*   SPDX-License-Identifier: BSD-3-Clause
2208f21cdSKrzysztof Smolinski  *   Copyright (C) 2022 Intel Corporation.
3208f21cdSKrzysztof Smolinski  *   All rights reserved.
4208f21cdSKrzysztof Smolinski  */
5208f21cdSKrzysztof Smolinski 
6208f21cdSKrzysztof Smolinski #include "bdev_raid.h"
7208f21cdSKrzysztof Smolinski 
8985b7c10SKrzysztof Smolinski #include "spdk/likely.h"
9208f21cdSKrzysztof Smolinski #include "spdk/log.h"
10208f21cdSKrzysztof Smolinski 
11208f21cdSKrzysztof Smolinski struct raid1_info {
12208f21cdSKrzysztof Smolinski 	/* The parent raid bdev */
13208f21cdSKrzysztof Smolinski 	struct raid_bdev *raid_bdev;
14208f21cdSKrzysztof Smolinski };
15208f21cdSKrzysztof Smolinski 
16a73acd9fSKrzysztof Smolinski struct raid1_io_channel {
17a73acd9fSKrzysztof Smolinski 	/* Array of per-base_bdev counters of outstanding read blocks on this channel */
18a73acd9fSKrzysztof Smolinski 	uint64_t read_blocks_outstanding[0];
19a73acd9fSKrzysztof Smolinski };
20985b7c10SKrzysztof Smolinski 
21a73acd9fSKrzysztof Smolinski static void
22a73acd9fSKrzysztof Smolinski raid1_channel_inc_read_counters(struct raid_bdev_io_channel *raid_ch, uint8_t idx,
23a73acd9fSKrzysztof Smolinski 				uint64_t num_blocks)
24a73acd9fSKrzysztof Smolinski {
256e03e49bSArtur Paszkiewicz 	struct raid1_io_channel *raid1_ch = raid_bdev_channel_get_module_ctx(raid_ch);
26a73acd9fSKrzysztof Smolinski 
27a73acd9fSKrzysztof Smolinski 	assert(raid1_ch->read_blocks_outstanding[idx] <= UINT64_MAX - num_blocks);
28a73acd9fSKrzysztof Smolinski 	raid1_ch->read_blocks_outstanding[idx] += num_blocks;
29a73acd9fSKrzysztof Smolinski }
30a73acd9fSKrzysztof Smolinski 
31a73acd9fSKrzysztof Smolinski static void
32a73acd9fSKrzysztof Smolinski raid1_channel_dec_read_counters(struct raid_bdev_io_channel *raid_ch, uint8_t idx,
33a73acd9fSKrzysztof Smolinski 				uint64_t num_blocks)
34a73acd9fSKrzysztof Smolinski {
356e03e49bSArtur Paszkiewicz 	struct raid1_io_channel *raid1_ch = raid_bdev_channel_get_module_ctx(raid_ch);
36a73acd9fSKrzysztof Smolinski 
37a73acd9fSKrzysztof Smolinski 	assert(raid1_ch->read_blocks_outstanding[idx] >= num_blocks);
38a73acd9fSKrzysztof Smolinski 	raid1_ch->read_blocks_outstanding[idx] -= num_blocks;
39a73acd9fSKrzysztof Smolinski }
40a73acd9fSKrzysztof Smolinski 
41a73acd9fSKrzysztof Smolinski static void
426e950b24SArtur Paszkiewicz raid1_init_ext_io_opts(struct spdk_bdev_ext_io_opts *opts, struct raid_bdev_io *raid_io)
436e950b24SArtur Paszkiewicz {
446e950b24SArtur Paszkiewicz 	memset(opts, 0, sizeof(*opts));
456e950b24SArtur Paszkiewicz 	opts->size = sizeof(*opts);
466e950b24SArtur Paszkiewicz 	opts->memory_domain = raid_io->memory_domain;
476e950b24SArtur Paszkiewicz 	opts->memory_domain_ctx = raid_io->memory_domain_ctx;
486e950b24SArtur Paszkiewicz 	opts->metadata = raid_io->md_buf;
496e950b24SArtur Paszkiewicz }
506e950b24SArtur Paszkiewicz 
516e950b24SArtur Paszkiewicz static void
52a73acd9fSKrzysztof Smolinski raid1_write_bdev_io_completion(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
53a73acd9fSKrzysztof Smolinski {
54a73acd9fSKrzysztof Smolinski 	struct raid_bdev_io *raid_io = cb_arg;
55a73acd9fSKrzysztof Smolinski 
56b0b0889eSArtur Paszkiewicz 	if (!success) {
57b0b0889eSArtur Paszkiewicz 		struct raid_base_bdev_info *base_info;
58b0b0889eSArtur Paszkiewicz 
59b0b0889eSArtur Paszkiewicz 		base_info = raid_bdev_channel_get_base_info(raid_io->raid_ch, bdev_io->bdev);
60b0b0889eSArtur Paszkiewicz 		if (base_info) {
61b0b0889eSArtur Paszkiewicz 			raid_bdev_fail_base_bdev(base_info);
62b0b0889eSArtur Paszkiewicz 		}
63b0b0889eSArtur Paszkiewicz 	}
64b0b0889eSArtur Paszkiewicz 
65d6aa653dSArtur Paszkiewicz 	spdk_bdev_free_io(bdev_io);
66d6aa653dSArtur Paszkiewicz 
67d6aa653dSArtur Paszkiewicz 	raid_bdev_io_complete_part(raid_io, 1, success ?
68d6aa653dSArtur Paszkiewicz 				   SPDK_BDEV_IO_STATUS_SUCCESS :
69d6aa653dSArtur Paszkiewicz 				   SPDK_BDEV_IO_STATUS_FAILED);
70a73acd9fSKrzysztof Smolinski }
71a73acd9fSKrzysztof Smolinski 
72cc94f303SArtur Paszkiewicz static struct raid_base_bdev_info *
73cc94f303SArtur Paszkiewicz raid1_get_read_io_base_bdev(struct raid_bdev_io *raid_io)
74cc94f303SArtur Paszkiewicz {
75cc94f303SArtur Paszkiewicz 	assert(raid_io->type == SPDK_BDEV_IO_TYPE_READ);
76cc94f303SArtur Paszkiewicz 	return &raid_io->raid_bdev->base_bdev_info[raid_io->base_bdev_io_submitted];
77cc94f303SArtur Paszkiewicz }
78cc94f303SArtur Paszkiewicz 
79cc94f303SArtur Paszkiewicz static void
80cc94f303SArtur Paszkiewicz raid1_correct_read_error_completion(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
81cc94f303SArtur Paszkiewicz {
82cc94f303SArtur Paszkiewicz 	struct raid_bdev_io *raid_io = cb_arg;
83cc94f303SArtur Paszkiewicz 
84cc94f303SArtur Paszkiewicz 	spdk_bdev_free_io(bdev_io);
85cc94f303SArtur Paszkiewicz 
86cc94f303SArtur Paszkiewicz 	if (!success) {
87cc94f303SArtur Paszkiewicz 		struct raid_base_bdev_info *base_info = raid1_get_read_io_base_bdev(raid_io);
88cc94f303SArtur Paszkiewicz 
89cc94f303SArtur Paszkiewicz 		/* Writing to the bdev that had the read error failed so fail the base bdev
90cc94f303SArtur Paszkiewicz 		 * but complete the raid_io successfully. */
91cc94f303SArtur Paszkiewicz 		raid_bdev_fail_base_bdev(base_info);
92cc94f303SArtur Paszkiewicz 	}
93cc94f303SArtur Paszkiewicz 
94cc94f303SArtur Paszkiewicz 	raid_bdev_io_complete(raid_io, SPDK_BDEV_IO_STATUS_SUCCESS);
95cc94f303SArtur Paszkiewicz }
96cc94f303SArtur Paszkiewicz 
97cc94f303SArtur Paszkiewicz static void
98cc94f303SArtur Paszkiewicz raid1_correct_read_error(void *_raid_io)
99cc94f303SArtur Paszkiewicz {
100cc94f303SArtur Paszkiewicz 	struct raid_bdev_io *raid_io = _raid_io;
101cc94f303SArtur Paszkiewicz 	struct raid_bdev *raid_bdev = raid_io->raid_bdev;
102cc94f303SArtur Paszkiewicz 	struct spdk_bdev_ext_io_opts io_opts;
103cc94f303SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info;
104cc94f303SArtur Paszkiewicz 	struct spdk_io_channel *base_ch;
105cc94f303SArtur Paszkiewicz 	uint8_t i;
106cc94f303SArtur Paszkiewicz 	int ret;
107cc94f303SArtur Paszkiewicz 
108cc94f303SArtur Paszkiewicz 	i = raid_io->base_bdev_io_submitted;
109cc94f303SArtur Paszkiewicz 	base_info = &raid_bdev->base_bdev_info[i];
110cc94f303SArtur Paszkiewicz 	base_ch = raid_bdev_channel_get_base_channel(raid_io->raid_ch, i);
111cc94f303SArtur Paszkiewicz 	assert(base_ch != NULL);
112cc94f303SArtur Paszkiewicz 
113cc94f303SArtur Paszkiewicz 	raid1_init_ext_io_opts(&io_opts, raid_io);
114cc94f303SArtur Paszkiewicz 	ret = raid_bdev_writev_blocks_ext(base_info, base_ch, raid_io->iovs, raid_io->iovcnt,
115cc94f303SArtur Paszkiewicz 					  raid_io->offset_blocks, raid_io->num_blocks,
116cc94f303SArtur Paszkiewicz 					  raid1_correct_read_error_completion, raid_io, &io_opts);
117cc94f303SArtur Paszkiewicz 	if (spdk_unlikely(ret != 0)) {
118cc94f303SArtur Paszkiewicz 		if (ret == -ENOMEM) {
119cc94f303SArtur Paszkiewicz 			raid_bdev_queue_io_wait(raid_io, spdk_bdev_desc_get_bdev(base_info->desc),
120cc94f303SArtur Paszkiewicz 						base_ch, raid1_correct_read_error);
121cc94f303SArtur Paszkiewicz 		} else {
122cc94f303SArtur Paszkiewicz 			raid_bdev_fail_base_bdev(base_info);
123cc94f303SArtur Paszkiewicz 			raid_bdev_io_complete(raid_io, SPDK_BDEV_IO_STATUS_SUCCESS);
124cc94f303SArtur Paszkiewicz 		}
125cc94f303SArtur Paszkiewicz 	}
126cc94f303SArtur Paszkiewicz }
127cc94f303SArtur Paszkiewicz 
128cc94f303SArtur Paszkiewicz static void raid1_read_other_base_bdev(void *_raid_io);
129cc94f303SArtur Paszkiewicz 
130cc94f303SArtur Paszkiewicz static void
131cc94f303SArtur Paszkiewicz raid1_read_other_completion(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
132cc94f303SArtur Paszkiewicz {
133cc94f303SArtur Paszkiewicz 	struct raid_bdev_io *raid_io = cb_arg;
134cc94f303SArtur Paszkiewicz 
135cc94f303SArtur Paszkiewicz 	spdk_bdev_free_io(bdev_io);
136cc94f303SArtur Paszkiewicz 
137cc94f303SArtur Paszkiewicz 	if (!success) {
138cc94f303SArtur Paszkiewicz 		assert(raid_io->base_bdev_io_remaining > 0);
139cc94f303SArtur Paszkiewicz 		raid_io->base_bdev_io_remaining--;
140cc94f303SArtur Paszkiewicz 		raid1_read_other_base_bdev(raid_io);
141cc94f303SArtur Paszkiewicz 		return;
142cc94f303SArtur Paszkiewicz 	}
143cc94f303SArtur Paszkiewicz 
144cc94f303SArtur Paszkiewicz 	/* try to correct the read error by writing data read from the other base bdev */
145cc94f303SArtur Paszkiewicz 	raid1_correct_read_error(raid_io);
146cc94f303SArtur Paszkiewicz }
147cc94f303SArtur Paszkiewicz 
148cc94f303SArtur Paszkiewicz static void
149cc94f303SArtur Paszkiewicz raid1_read_other_base_bdev(void *_raid_io)
150cc94f303SArtur Paszkiewicz {
151cc94f303SArtur Paszkiewicz 	struct raid_bdev_io *raid_io = _raid_io;
152cc94f303SArtur Paszkiewicz 	struct raid_bdev *raid_bdev = raid_io->raid_bdev;
153cc94f303SArtur Paszkiewicz 	struct spdk_bdev_ext_io_opts io_opts;
154cc94f303SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info;
155cc94f303SArtur Paszkiewicz 	struct spdk_io_channel *base_ch;
156cc94f303SArtur Paszkiewicz 	uint8_t i;
157cc94f303SArtur Paszkiewicz 	int ret;
158cc94f303SArtur Paszkiewicz 
159cc94f303SArtur Paszkiewicz 	for (i = raid_bdev->num_base_bdevs - raid_io->base_bdev_io_remaining; i < raid_bdev->num_base_bdevs;
160cc94f303SArtur Paszkiewicz 	     i++) {
161cc94f303SArtur Paszkiewicz 		base_info = &raid_bdev->base_bdev_info[i];
162cc94f303SArtur Paszkiewicz 		base_ch = raid_bdev_channel_get_base_channel(raid_io->raid_ch, i);
163cc94f303SArtur Paszkiewicz 
164cc94f303SArtur Paszkiewicz 		if (base_ch == NULL || i == raid_io->base_bdev_io_submitted) {
165cc94f303SArtur Paszkiewicz 			raid_io->base_bdev_io_remaining--;
166cc94f303SArtur Paszkiewicz 			continue;
167cc94f303SArtur Paszkiewicz 		}
168cc94f303SArtur Paszkiewicz 
169cc94f303SArtur Paszkiewicz 		raid1_init_ext_io_opts(&io_opts, raid_io);
170cc94f303SArtur Paszkiewicz 		ret = raid_bdev_readv_blocks_ext(base_info, base_ch, raid_io->iovs, raid_io->iovcnt,
171cc94f303SArtur Paszkiewicz 						 raid_io->offset_blocks, raid_io->num_blocks,
172cc94f303SArtur Paszkiewicz 						 raid1_read_other_completion, raid_io, &io_opts);
173cc94f303SArtur Paszkiewicz 		if (spdk_unlikely(ret != 0)) {
174cc94f303SArtur Paszkiewicz 			if (ret == -ENOMEM) {
175cc94f303SArtur Paszkiewicz 				raid_bdev_queue_io_wait(raid_io, spdk_bdev_desc_get_bdev(base_info->desc),
176cc94f303SArtur Paszkiewicz 							base_ch, raid1_read_other_base_bdev);
177cc94f303SArtur Paszkiewicz 			} else {
178cc94f303SArtur Paszkiewicz 				break;
179cc94f303SArtur Paszkiewicz 			}
180cc94f303SArtur Paszkiewicz 		}
181cc94f303SArtur Paszkiewicz 		return;
182cc94f303SArtur Paszkiewicz 	}
183cc94f303SArtur Paszkiewicz 
184cc94f303SArtur Paszkiewicz 	base_info = raid1_get_read_io_base_bdev(raid_io);
185cc94f303SArtur Paszkiewicz 	raid_bdev_fail_base_bdev(base_info);
186cc94f303SArtur Paszkiewicz 
187cc94f303SArtur Paszkiewicz 	raid_bdev_io_complete(raid_io, SPDK_BDEV_IO_STATUS_FAILED);
188cc94f303SArtur Paszkiewicz }
189cc94f303SArtur Paszkiewicz 
190a73acd9fSKrzysztof Smolinski static void
191a73acd9fSKrzysztof Smolinski raid1_read_bdev_io_completion(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
192a73acd9fSKrzysztof Smolinski {
193a73acd9fSKrzysztof Smolinski 	struct raid_bdev_io *raid_io = cb_arg;
194a73acd9fSKrzysztof Smolinski 
195d6aa653dSArtur Paszkiewicz 	spdk_bdev_free_io(bdev_io);
196d6aa653dSArtur Paszkiewicz 
197a73acd9fSKrzysztof Smolinski 	raid1_channel_dec_read_counters(raid_io->raid_ch, raid_io->base_bdev_io_submitted,
198a4e1703eSArtur Paszkiewicz 					raid_io->num_blocks);
199a73acd9fSKrzysztof Smolinski 
200cc94f303SArtur Paszkiewicz 	if (!success) {
201cc94f303SArtur Paszkiewicz 		raid_io->base_bdev_io_remaining = raid_io->raid_bdev->num_base_bdevs;
202cc94f303SArtur Paszkiewicz 		raid1_read_other_base_bdev(raid_io);
203cc94f303SArtur Paszkiewicz 		return;
204cc94f303SArtur Paszkiewicz 	}
205cc94f303SArtur Paszkiewicz 
206cc94f303SArtur Paszkiewicz 	raid_bdev_io_complete(raid_io, SPDK_BDEV_IO_STATUS_SUCCESS);
207a73acd9fSKrzysztof Smolinski }
208a73acd9fSKrzysztof Smolinski 
209985b7c10SKrzysztof Smolinski static void raid1_submit_rw_request(struct raid_bdev_io *raid_io);
210985b7c10SKrzysztof Smolinski 
211985b7c10SKrzysztof Smolinski static void
212985b7c10SKrzysztof Smolinski _raid1_submit_rw_request(void *_raid_io)
213985b7c10SKrzysztof Smolinski {
214985b7c10SKrzysztof Smolinski 	struct raid_bdev_io *raid_io = _raid_io;
215985b7c10SKrzysztof Smolinski 
216985b7c10SKrzysztof Smolinski 	raid1_submit_rw_request(raid_io);
217985b7c10SKrzysztof Smolinski }
218985b7c10SKrzysztof Smolinski 
219a73acd9fSKrzysztof Smolinski static uint8_t
220030dab89SArtur Paszkiewicz raid1_channel_next_read_base_bdev(struct raid_bdev *raid_bdev, struct raid_bdev_io_channel *raid_ch)
221a73acd9fSKrzysztof Smolinski {
2226e03e49bSArtur Paszkiewicz 	struct raid1_io_channel *raid1_ch = raid_bdev_channel_get_module_ctx(raid_ch);
223a73acd9fSKrzysztof Smolinski 	uint64_t read_blocks_min = UINT64_MAX;
224a73acd9fSKrzysztof Smolinski 	uint8_t idx = UINT8_MAX;
225a73acd9fSKrzysztof Smolinski 	uint8_t i;
226a73acd9fSKrzysztof Smolinski 
227030dab89SArtur Paszkiewicz 	for (i = 0; i < raid_bdev->num_base_bdevs; i++) {
2286e03e49bSArtur Paszkiewicz 		if (raid_bdev_channel_get_base_channel(raid_ch, i) != NULL &&
229a73acd9fSKrzysztof Smolinski 		    raid1_ch->read_blocks_outstanding[i] < read_blocks_min) {
230a73acd9fSKrzysztof Smolinski 			read_blocks_min = raid1_ch->read_blocks_outstanding[i];
231a73acd9fSKrzysztof Smolinski 			idx = i;
232a73acd9fSKrzysztof Smolinski 		}
233a73acd9fSKrzysztof Smolinski 	}
234a73acd9fSKrzysztof Smolinski 
235a73acd9fSKrzysztof Smolinski 	return idx;
236a73acd9fSKrzysztof Smolinski }
237a73acd9fSKrzysztof Smolinski 
238985b7c10SKrzysztof Smolinski static int
239985b7c10SKrzysztof Smolinski raid1_submit_read_request(struct raid_bdev_io *raid_io)
240985b7c10SKrzysztof Smolinski {
241985b7c10SKrzysztof Smolinski 	struct raid_bdev *raid_bdev = raid_io->raid_bdev;
242a73acd9fSKrzysztof Smolinski 	struct raid_bdev_io_channel *raid_ch = raid_io->raid_ch;
24355f94793SKonrad Sztyber 	struct spdk_bdev_ext_io_opts io_opts;
244597fbea9SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info;
245a73acd9fSKrzysztof Smolinski 	struct spdk_io_channel *base_ch;
246a73acd9fSKrzysztof Smolinski 	uint8_t idx;
247985b7c10SKrzysztof Smolinski 	int ret;
248985b7c10SKrzysztof Smolinski 
249030dab89SArtur Paszkiewicz 	idx = raid1_channel_next_read_base_bdev(raid_bdev, raid_ch);
250a73acd9fSKrzysztof Smolinski 	if (spdk_unlikely(idx == UINT8_MAX)) {
251597fbea9SArtur Paszkiewicz 		raid_bdev_io_complete(raid_io, SPDK_BDEV_IO_STATUS_FAILED);
252597fbea9SArtur Paszkiewicz 		return 0;
253597fbea9SArtur Paszkiewicz 	}
254597fbea9SArtur Paszkiewicz 
255a73acd9fSKrzysztof Smolinski 	base_info = &raid_bdev->base_bdev_info[idx];
2566e03e49bSArtur Paszkiewicz 	base_ch = raid_bdev_channel_get_base_channel(raid_ch, idx);
257985b7c10SKrzysztof Smolinski 
258a4e1703eSArtur Paszkiewicz 	raid1_init_ext_io_opts(&io_opts, raid_io);
259a4e1703eSArtur Paszkiewicz 	ret = raid_bdev_readv_blocks_ext(base_info, base_ch, raid_io->iovs, raid_io->iovcnt,
260a4e1703eSArtur Paszkiewicz 					 raid_io->offset_blocks, raid_io->num_blocks,
261a4e1703eSArtur Paszkiewicz 					 raid1_read_bdev_io_completion, raid_io, &io_opts);
262985b7c10SKrzysztof Smolinski 
263985b7c10SKrzysztof Smolinski 	if (spdk_likely(ret == 0)) {
264a4e1703eSArtur Paszkiewicz 		raid1_channel_inc_read_counters(raid_ch, idx, raid_io->num_blocks);
265a73acd9fSKrzysztof Smolinski 		raid_io->base_bdev_io_submitted = idx;
266985b7c10SKrzysztof Smolinski 	} else if (spdk_unlikely(ret == -ENOMEM)) {
2678d1993a5SArtur Paszkiewicz 		raid_bdev_queue_io_wait(raid_io, spdk_bdev_desc_get_bdev(base_info->desc),
2688d1993a5SArtur Paszkiewicz 					base_ch, _raid1_submit_rw_request);
269985b7c10SKrzysztof Smolinski 		return 0;
270985b7c10SKrzysztof Smolinski 	}
271985b7c10SKrzysztof Smolinski 
272985b7c10SKrzysztof Smolinski 	return ret;
273985b7c10SKrzysztof Smolinski }
274985b7c10SKrzysztof Smolinski 
275985b7c10SKrzysztof Smolinski static int
276985b7c10SKrzysztof Smolinski raid1_submit_write_request(struct raid_bdev_io *raid_io)
277985b7c10SKrzysztof Smolinski {
278985b7c10SKrzysztof Smolinski 	struct raid_bdev *raid_bdev = raid_io->raid_bdev;
27955f94793SKonrad Sztyber 	struct spdk_bdev_ext_io_opts io_opts;
280985b7c10SKrzysztof Smolinski 	struct raid_base_bdev_info *base_info;
281985b7c10SKrzysztof Smolinski 	struct spdk_io_channel *base_ch;
282597fbea9SArtur Paszkiewicz 	uint8_t idx;
283985b7c10SKrzysztof Smolinski 	uint64_t base_bdev_io_not_submitted;
284985b7c10SKrzysztof Smolinski 	int ret = 0;
285985b7c10SKrzysztof Smolinski 
286985b7c10SKrzysztof Smolinski 	if (raid_io->base_bdev_io_submitted == 0) {
287985b7c10SKrzysztof Smolinski 		raid_io->base_bdev_io_remaining = raid_bdev->num_base_bdevs;
288b0b0889eSArtur Paszkiewicz 		raid_bdev_io_set_default_status(raid_io, SPDK_BDEV_IO_STATUS_FAILED);
289985b7c10SKrzysztof Smolinski 	}
290985b7c10SKrzysztof Smolinski 
291a4e1703eSArtur Paszkiewicz 	raid1_init_ext_io_opts(&io_opts, raid_io);
292597fbea9SArtur Paszkiewicz 	for (idx = raid_io->base_bdev_io_submitted; idx < raid_bdev->num_base_bdevs; idx++) {
293985b7c10SKrzysztof Smolinski 		base_info = &raid_bdev->base_bdev_info[idx];
2946e03e49bSArtur Paszkiewicz 		base_ch = raid_bdev_channel_get_base_channel(raid_io->raid_ch, idx);
295985b7c10SKrzysztof Smolinski 
296597fbea9SArtur Paszkiewicz 		if (base_ch == NULL) {
297597fbea9SArtur Paszkiewicz 			/* skip a missing base bdev's slot */
298597fbea9SArtur Paszkiewicz 			raid_io->base_bdev_io_submitted++;
299b0b0889eSArtur Paszkiewicz 			raid_bdev_io_complete_part(raid_io, 1, SPDK_BDEV_IO_STATUS_FAILED);
300597fbea9SArtur Paszkiewicz 			continue;
301597fbea9SArtur Paszkiewicz 		}
302597fbea9SArtur Paszkiewicz 
303a4e1703eSArtur Paszkiewicz 		ret = raid_bdev_writev_blocks_ext(base_info, base_ch, raid_io->iovs, raid_io->iovcnt,
304a4e1703eSArtur Paszkiewicz 						  raid_io->offset_blocks, raid_io->num_blocks,
305a4e1703eSArtur Paszkiewicz 						  raid1_write_bdev_io_completion, raid_io, &io_opts);
306985b7c10SKrzysztof Smolinski 		if (spdk_unlikely(ret != 0)) {
307985b7c10SKrzysztof Smolinski 			if (spdk_unlikely(ret == -ENOMEM)) {
3088d1993a5SArtur Paszkiewicz 				raid_bdev_queue_io_wait(raid_io, spdk_bdev_desc_get_bdev(base_info->desc),
3098d1993a5SArtur Paszkiewicz 							base_ch, _raid1_submit_rw_request);
310985b7c10SKrzysztof Smolinski 				return 0;
311985b7c10SKrzysztof Smolinski 			}
312985b7c10SKrzysztof Smolinski 
313985b7c10SKrzysztof Smolinski 			base_bdev_io_not_submitted = raid_bdev->num_base_bdevs -
314985b7c10SKrzysztof Smolinski 						     raid_io->base_bdev_io_submitted;
315985b7c10SKrzysztof Smolinski 			raid_bdev_io_complete_part(raid_io, base_bdev_io_not_submitted,
316985b7c10SKrzysztof Smolinski 						   SPDK_BDEV_IO_STATUS_FAILED);
317985b7c10SKrzysztof Smolinski 			return 0;
318985b7c10SKrzysztof Smolinski 		}
319985b7c10SKrzysztof Smolinski 
320985b7c10SKrzysztof Smolinski 		raid_io->base_bdev_io_submitted++;
321985b7c10SKrzysztof Smolinski 	}
322985b7c10SKrzysztof Smolinski 
323597fbea9SArtur Paszkiewicz 	if (raid_io->base_bdev_io_submitted == 0) {
324597fbea9SArtur Paszkiewicz 		ret = -ENODEV;
325597fbea9SArtur Paszkiewicz 	}
326597fbea9SArtur Paszkiewicz 
327985b7c10SKrzysztof Smolinski 	return ret;
328985b7c10SKrzysztof Smolinski }
329985b7c10SKrzysztof Smolinski 
330985b7c10SKrzysztof Smolinski static void
331208f21cdSKrzysztof Smolinski raid1_submit_rw_request(struct raid_bdev_io *raid_io)
332208f21cdSKrzysztof Smolinski {
333985b7c10SKrzysztof Smolinski 	int ret;
334985b7c10SKrzysztof Smolinski 
335a4e1703eSArtur Paszkiewicz 	switch (raid_io->type) {
336985b7c10SKrzysztof Smolinski 	case SPDK_BDEV_IO_TYPE_READ:
337985b7c10SKrzysztof Smolinski 		ret = raid1_submit_read_request(raid_io);
338985b7c10SKrzysztof Smolinski 		break;
339985b7c10SKrzysztof Smolinski 	case SPDK_BDEV_IO_TYPE_WRITE:
340985b7c10SKrzysztof Smolinski 		ret = raid1_submit_write_request(raid_io);
341985b7c10SKrzysztof Smolinski 		break;
342985b7c10SKrzysztof Smolinski 	default:
343985b7c10SKrzysztof Smolinski 		ret = -EINVAL;
344985b7c10SKrzysztof Smolinski 		break;
345985b7c10SKrzysztof Smolinski 	}
346985b7c10SKrzysztof Smolinski 
347985b7c10SKrzysztof Smolinski 	if (spdk_unlikely(ret != 0)) {
348208f21cdSKrzysztof Smolinski 		raid_bdev_io_complete(raid_io, SPDK_BDEV_IO_STATUS_FAILED);
349208f21cdSKrzysztof Smolinski 	}
350985b7c10SKrzysztof Smolinski }
351208f21cdSKrzysztof Smolinski 
352a73acd9fSKrzysztof Smolinski static void
353a73acd9fSKrzysztof Smolinski raid1_ioch_destroy(void *io_device, void *ctx_buf)
354a73acd9fSKrzysztof Smolinski {
355a73acd9fSKrzysztof Smolinski }
356a73acd9fSKrzysztof Smolinski 
357a73acd9fSKrzysztof Smolinski static int
358a73acd9fSKrzysztof Smolinski raid1_ioch_create(void *io_device, void *ctx_buf)
359a73acd9fSKrzysztof Smolinski {
360a73acd9fSKrzysztof Smolinski 	return 0;
361a73acd9fSKrzysztof Smolinski }
362a73acd9fSKrzysztof Smolinski 
363a73acd9fSKrzysztof Smolinski static void
364a73acd9fSKrzysztof Smolinski raid1_io_device_unregister_done(void *io_device)
365a73acd9fSKrzysztof Smolinski {
366a73acd9fSKrzysztof Smolinski 	struct raid1_info *r1info = io_device;
367a73acd9fSKrzysztof Smolinski 
368a73acd9fSKrzysztof Smolinski 	raid_bdev_module_stop_done(r1info->raid_bdev);
369a73acd9fSKrzysztof Smolinski 
370a73acd9fSKrzysztof Smolinski 	free(r1info);
371a73acd9fSKrzysztof Smolinski }
372a73acd9fSKrzysztof Smolinski 
373208f21cdSKrzysztof Smolinski static int
374208f21cdSKrzysztof Smolinski raid1_start(struct raid_bdev *raid_bdev)
375208f21cdSKrzysztof Smolinski {
376208f21cdSKrzysztof Smolinski 	uint64_t min_blockcnt = UINT64_MAX;
377208f21cdSKrzysztof Smolinski 	struct raid_base_bdev_info *base_info;
378208f21cdSKrzysztof Smolinski 	struct raid1_info *r1info;
379a73acd9fSKrzysztof Smolinski 	char name[256];
380208f21cdSKrzysztof Smolinski 
381208f21cdSKrzysztof Smolinski 	r1info = calloc(1, sizeof(*r1info));
382208f21cdSKrzysztof Smolinski 	if (!r1info) {
383208f21cdSKrzysztof Smolinski 		SPDK_ERRLOG("Failed to allocate RAID1 info device structure\n");
384208f21cdSKrzysztof Smolinski 		return -ENOMEM;
385208f21cdSKrzysztof Smolinski 	}
386208f21cdSKrzysztof Smolinski 	r1info->raid_bdev = raid_bdev;
387208f21cdSKrzysztof Smolinski 
388208f21cdSKrzysztof Smolinski 	RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
389deed7d2fSArtur Paszkiewicz 		min_blockcnt = spdk_min(min_blockcnt, base_info->data_size);
390deed7d2fSArtur Paszkiewicz 	}
391deed7d2fSArtur Paszkiewicz 
392deed7d2fSArtur Paszkiewicz 	RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
393deed7d2fSArtur Paszkiewicz 		base_info->data_size = min_blockcnt;
394208f21cdSKrzysztof Smolinski 	}
395208f21cdSKrzysztof Smolinski 
396208f21cdSKrzysztof Smolinski 	raid_bdev->bdev.blockcnt = min_blockcnt;
397208f21cdSKrzysztof Smolinski 	raid_bdev->module_private = r1info;
398208f21cdSKrzysztof Smolinski 
399a73acd9fSKrzysztof Smolinski 	snprintf(name, sizeof(name), "raid1_%s", raid_bdev->bdev.name);
400a73acd9fSKrzysztof Smolinski 	spdk_io_device_register(r1info, raid1_ioch_create, raid1_ioch_destroy,
401a73acd9fSKrzysztof Smolinski 				sizeof(struct raid1_io_channel) + raid_bdev->num_base_bdevs * sizeof(uint64_t),
402a73acd9fSKrzysztof Smolinski 				name);
403a73acd9fSKrzysztof Smolinski 
404208f21cdSKrzysztof Smolinski 	return 0;
405208f21cdSKrzysztof Smolinski }
406208f21cdSKrzysztof Smolinski 
407208f21cdSKrzysztof Smolinski static bool
408208f21cdSKrzysztof Smolinski raid1_stop(struct raid_bdev *raid_bdev)
409208f21cdSKrzysztof Smolinski {
410208f21cdSKrzysztof Smolinski 	struct raid1_info *r1info = raid_bdev->module_private;
411208f21cdSKrzysztof Smolinski 
412a73acd9fSKrzysztof Smolinski 	spdk_io_device_unregister(r1info, raid1_io_device_unregister_done);
413208f21cdSKrzysztof Smolinski 
414a73acd9fSKrzysztof Smolinski 	return false;
415a73acd9fSKrzysztof Smolinski }
416a73acd9fSKrzysztof Smolinski 
417a73acd9fSKrzysztof Smolinski static struct spdk_io_channel *
418a73acd9fSKrzysztof Smolinski raid1_get_io_channel(struct raid_bdev *raid_bdev)
419a73acd9fSKrzysztof Smolinski {
420a73acd9fSKrzysztof Smolinski 	struct raid1_info *r1info = raid_bdev->module_private;
421a73acd9fSKrzysztof Smolinski 
422a73acd9fSKrzysztof Smolinski 	return spdk_get_io_channel(r1info);
423208f21cdSKrzysztof Smolinski }
424208f21cdSKrzysztof Smolinski 
425aefa99f1SArtur Paszkiewicz static void
426aefa99f1SArtur Paszkiewicz raid1_process_write_completed(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
427aefa99f1SArtur Paszkiewicz {
428aefa99f1SArtur Paszkiewicz 	struct raid_bdev_process_request *process_req = cb_arg;
429aefa99f1SArtur Paszkiewicz 
430aefa99f1SArtur Paszkiewicz 	spdk_bdev_free_io(bdev_io);
431aefa99f1SArtur Paszkiewicz 
432aefa99f1SArtur Paszkiewicz 	raid_bdev_process_request_complete(process_req, success ? 0 : -EIO);
433aefa99f1SArtur Paszkiewicz }
434aefa99f1SArtur Paszkiewicz 
435aefa99f1SArtur Paszkiewicz static void raid1_process_submit_write(struct raid_bdev_process_request *process_req);
436aefa99f1SArtur Paszkiewicz 
437aefa99f1SArtur Paszkiewicz static void
438aefa99f1SArtur Paszkiewicz _raid1_process_submit_write(void *ctx)
439aefa99f1SArtur Paszkiewicz {
440aefa99f1SArtur Paszkiewicz 	struct raid_bdev_process_request *process_req = ctx;
441aefa99f1SArtur Paszkiewicz 
442aefa99f1SArtur Paszkiewicz 	raid1_process_submit_write(process_req);
443aefa99f1SArtur Paszkiewicz }
444aefa99f1SArtur Paszkiewicz 
445aefa99f1SArtur Paszkiewicz static void
446aefa99f1SArtur Paszkiewicz raid1_process_submit_write(struct raid_bdev_process_request *process_req)
447aefa99f1SArtur Paszkiewicz {
448aefa99f1SArtur Paszkiewicz 	struct raid_bdev_io *raid_io = &process_req->raid_io;
449aefa99f1SArtur Paszkiewicz 	struct spdk_bdev_ext_io_opts io_opts;
450aefa99f1SArtur Paszkiewicz 	int ret;
451aefa99f1SArtur Paszkiewicz 
452aefa99f1SArtur Paszkiewicz 	raid1_init_ext_io_opts(&io_opts, raid_io);
453aefa99f1SArtur Paszkiewicz 	ret = raid_bdev_writev_blocks_ext(process_req->target, process_req->target_ch,
454aefa99f1SArtur Paszkiewicz 					  raid_io->iovs, raid_io->iovcnt,
455aefa99f1SArtur Paszkiewicz 					  raid_io->offset_blocks, raid_io->num_blocks,
456aefa99f1SArtur Paszkiewicz 					  raid1_process_write_completed, process_req, &io_opts);
457aefa99f1SArtur Paszkiewicz 	if (spdk_unlikely(ret != 0)) {
458aefa99f1SArtur Paszkiewicz 		if (ret == -ENOMEM) {
459aefa99f1SArtur Paszkiewicz 			raid_bdev_queue_io_wait(raid_io, spdk_bdev_desc_get_bdev(process_req->target->desc),
460aefa99f1SArtur Paszkiewicz 						process_req->target_ch, _raid1_process_submit_write);
461aefa99f1SArtur Paszkiewicz 		} else {
462aefa99f1SArtur Paszkiewicz 			raid_bdev_process_request_complete(process_req, ret);
463aefa99f1SArtur Paszkiewicz 		}
464aefa99f1SArtur Paszkiewicz 	}
465aefa99f1SArtur Paszkiewicz }
466aefa99f1SArtur Paszkiewicz 
467aefa99f1SArtur Paszkiewicz static void
468aefa99f1SArtur Paszkiewicz raid1_process_read_completed(struct raid_bdev_io *raid_io, enum spdk_bdev_io_status status)
469aefa99f1SArtur Paszkiewicz {
470aefa99f1SArtur Paszkiewicz 	struct raid_bdev_process_request *process_req = SPDK_CONTAINEROF(raid_io,
471aefa99f1SArtur Paszkiewicz 			struct raid_bdev_process_request, raid_io);
472aefa99f1SArtur Paszkiewicz 
473aefa99f1SArtur Paszkiewicz 	if (status != SPDK_BDEV_IO_STATUS_SUCCESS) {
474aefa99f1SArtur Paszkiewicz 		raid_bdev_process_request_complete(process_req, -EIO);
475aefa99f1SArtur Paszkiewicz 		return;
476aefa99f1SArtur Paszkiewicz 	}
477aefa99f1SArtur Paszkiewicz 
478aefa99f1SArtur Paszkiewicz 	raid1_process_submit_write(process_req);
479aefa99f1SArtur Paszkiewicz }
480aefa99f1SArtur Paszkiewicz 
481aefa99f1SArtur Paszkiewicz static int
482aefa99f1SArtur Paszkiewicz raid1_submit_process_request(struct raid_bdev_process_request *process_req,
483aefa99f1SArtur Paszkiewicz 			     struct raid_bdev_io_channel *raid_ch)
484aefa99f1SArtur Paszkiewicz {
485aefa99f1SArtur Paszkiewicz 	struct raid_bdev_io *raid_io = &process_req->raid_io;
486aefa99f1SArtur Paszkiewicz 	int ret;
487aefa99f1SArtur Paszkiewicz 
488aefa99f1SArtur Paszkiewicz 	raid_bdev_io_init(raid_io, raid_ch, SPDK_BDEV_IO_TYPE_READ,
489aefa99f1SArtur Paszkiewicz 			  process_req->offset_blocks, process_req->num_blocks,
490aefa99f1SArtur Paszkiewicz 			  &process_req->iov, 1, process_req->md_buf, NULL, NULL);
491aefa99f1SArtur Paszkiewicz 	raid_io->completion_cb = raid1_process_read_completed;
492aefa99f1SArtur Paszkiewicz 
493aefa99f1SArtur Paszkiewicz 	ret = raid1_submit_read_request(raid_io);
494aefa99f1SArtur Paszkiewicz 	if (spdk_likely(ret == 0)) {
495aefa99f1SArtur Paszkiewicz 		return process_req->num_blocks;
496aefa99f1SArtur Paszkiewicz 	} else if (ret < 0) {
497aefa99f1SArtur Paszkiewicz 		return ret;
498aefa99f1SArtur Paszkiewicz 	} else {
499aefa99f1SArtur Paszkiewicz 		return -EINVAL;
500aefa99f1SArtur Paszkiewicz 	}
501aefa99f1SArtur Paszkiewicz }
502aefa99f1SArtur Paszkiewicz 
503*3b9baa5fSLoïc Yavercovski static bool
504*3b9baa5fSLoïc Yavercovski raid1_resize(struct raid_bdev *raid_bdev)
505*3b9baa5fSLoïc Yavercovski {
506*3b9baa5fSLoïc Yavercovski 	int rc;
507*3b9baa5fSLoïc Yavercovski 	uint64_t min_blockcnt = UINT64_MAX;
508*3b9baa5fSLoïc Yavercovski 	struct raid_base_bdev_info *base_info;
509*3b9baa5fSLoïc Yavercovski 
510*3b9baa5fSLoïc Yavercovski 	RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
511*3b9baa5fSLoïc Yavercovski 		struct spdk_bdev *base_bdev;
512*3b9baa5fSLoïc Yavercovski 
513*3b9baa5fSLoïc Yavercovski 		if (base_info->desc == NULL) {
514*3b9baa5fSLoïc Yavercovski 			continue;
515*3b9baa5fSLoïc Yavercovski 		}
516*3b9baa5fSLoïc Yavercovski 		base_bdev = spdk_bdev_desc_get_bdev(base_info->desc);
517*3b9baa5fSLoïc Yavercovski 		min_blockcnt = spdk_min(min_blockcnt, base_bdev->blockcnt - base_info->data_offset);
518*3b9baa5fSLoïc Yavercovski 	}
519*3b9baa5fSLoïc Yavercovski 
520*3b9baa5fSLoïc Yavercovski 	if (min_blockcnt == raid_bdev->bdev.blockcnt) {
521*3b9baa5fSLoïc Yavercovski 		return false;
522*3b9baa5fSLoïc Yavercovski 	}
523*3b9baa5fSLoïc Yavercovski 
524*3b9baa5fSLoïc Yavercovski 	rc = spdk_bdev_notify_blockcnt_change(&raid_bdev->bdev, min_blockcnt);
525*3b9baa5fSLoïc Yavercovski 	if (rc != 0) {
526*3b9baa5fSLoïc Yavercovski 		SPDK_ERRLOG("Failed to notify blockcount change\n");
527*3b9baa5fSLoïc Yavercovski 		return false;
528*3b9baa5fSLoïc Yavercovski 	}
529*3b9baa5fSLoïc Yavercovski 
530*3b9baa5fSLoïc Yavercovski 	RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
531*3b9baa5fSLoïc Yavercovski 		base_info->data_size = min_blockcnt;
532*3b9baa5fSLoïc Yavercovski 	}
533*3b9baa5fSLoïc Yavercovski 	return true;
534*3b9baa5fSLoïc Yavercovski }
535*3b9baa5fSLoïc Yavercovski 
536208f21cdSKrzysztof Smolinski static struct raid_bdev_module g_raid1_module = {
537208f21cdSKrzysztof Smolinski 	.level = RAID1,
538208f21cdSKrzysztof Smolinski 	.base_bdevs_min = 2,
539208f21cdSKrzysztof Smolinski 	.base_bdevs_constraint = {CONSTRAINT_MIN_BASE_BDEVS_OPERATIONAL, 1},
54072672d49SArtur Paszkiewicz 	.memory_domains_supported = true,
541208f21cdSKrzysztof Smolinski 	.start = raid1_start,
542208f21cdSKrzysztof Smolinski 	.stop = raid1_stop,
543208f21cdSKrzysztof Smolinski 	.submit_rw_request = raid1_submit_rw_request,
544a73acd9fSKrzysztof Smolinski 	.get_io_channel = raid1_get_io_channel,
545aefa99f1SArtur Paszkiewicz 	.submit_process_request = raid1_submit_process_request,
546*3b9baa5fSLoïc Yavercovski 	.resize = raid1_resize,
547208f21cdSKrzysztof Smolinski };
548208f21cdSKrzysztof Smolinski RAID_MODULE_REGISTER(&g_raid1_module)
549208f21cdSKrzysztof Smolinski 
550208f21cdSKrzysztof Smolinski SPDK_LOG_REGISTER_COMPONENT(bdev_raid1)
551