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