/* * Copyright (c) 2025 Miroslav Cimerman * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @addtogroup hr * @{ */ /** * @file */ #include #include #include #include #include #include #include #include #include "io.h" #include "parity_stripe.h" #include "util.h" #include "var.h" /** Wrapper for block_write_direct(), never returns ENOMEM */ errno_t hr_write_direct(service_id_t service_id, uint64_t ba, size_t cnt, const void *data) { errno_t rc; while ((rc = block_write_direct(service_id, ba, cnt, data)) == ENOMEM) fibril_usleep(MSEC2USEC(250)); /* sleep 250ms */ if (rc == EAGAIN) rc = EIO; return rc; } /** Wrapper for block_read_direct(), never returns ENOMEM */ errno_t hr_read_direct(service_id_t service_id, uint64_t ba, size_t cnt, void *data) { errno_t rc; while ((rc = block_read_direct(service_id, ba, cnt, data)) == ENOMEM) fibril_usleep(MSEC2USEC(250)); /* sleep 250ms */ if (rc == EAGAIN) rc = EIO; return rc; } /** Wrapper for block_sync_cache(), never returns ENOMEM */ errno_t hr_sync_cache(service_id_t service_id, uint64_t ba, size_t cnt) { errno_t rc; while ((rc = block_sync_cache(service_id, ba, cnt)) == ENOMEM) fibril_usleep(MSEC2USEC(250)); /* sleep 250ms */ if (rc == EAGAIN) rc = EIO; return rc; } errno_t hr_io_worker(void *arg) { hr_io_t *io = arg; errno_t rc; size_t e = io->extent; hr_extent_t *extents = (hr_extent_t *)&io->vol->extents; switch (io->type) { case HR_BD_READ: rc = hr_read_direct(extents[e].svc_id, io->ba, io->cnt, io->data_read); break; case HR_BD_WRITE: rc = hr_write_direct(extents[e].svc_id, io->ba, io->cnt, io->data_write); break; default: assert(0); } if (io->vol->level == HR_LVL_1) { atomic_store_explicit(&io->vol->last_ext_pos_arr[e], io->ba + io->cnt - 1, memory_order_relaxed); } if (rc != EOK) io->vol->hr_ops.ext_state_cb(io->vol, io->extent, rc); return rc; } errno_t hr_io_raid5_basic_reader(void *arg) { errno_t rc; hr_io_raid5_t *io = arg; size_t ext_idx = io->extent; hr_extent_t *extents = (hr_extent_t *)&io->vol->extents; rc = hr_read_direct(extents[ext_idx].svc_id, io->ba, io->cnt, io->data_read); if (rc != EOK) io->vol->hr_ops.ext_state_cb(io->vol, io->extent, rc); return rc; } errno_t hr_io_raid5_reader(void *arg) { errno_t rc; hr_io_raid5_t *io = arg; hr_stripe_t *stripe = io->stripe; size_t ext_idx = io->extent; hr_extent_t *extents = (hr_extent_t *)&io->vol->extents; rc = hr_read_direct(extents[ext_idx].svc_id, io->ba, io->cnt, io->data_read); if (rc != EOK) { hr_stripe_parity_abort(stripe); io->vol->hr_ops.ext_state_cb(io->vol, io->extent, rc); } hr_stripe_commit_parity(stripe, io->strip_off, io->data_read, io->cnt * io->vol->bsize); return rc; } errno_t hr_io_raid5_basic_writer(void *arg) { errno_t rc; hr_io_raid5_t *io = arg; size_t ext_idx = io->extent; hr_extent_t *extents = (hr_extent_t *)&io->vol->extents; rc = hr_write_direct(extents[ext_idx].svc_id, io->ba, io->cnt, io->data_write); if (rc != EOK) io->vol->hr_ops.ext_state_cb(io->vol, io->extent, rc); return rc; } errno_t hr_io_raid5_writer(void *arg) { errno_t rc; hr_io_raid5_t *io = arg; hr_stripe_t *stripe = io->stripe; size_t ext_idx = io->extent; hr_extent_t *extents = (hr_extent_t *)&io->vol->extents; hr_stripe_commit_parity(stripe, io->strip_off, io->data_write, io->cnt * io->vol->bsize); hr_stripe_wait_for_parity_commits(stripe); if (stripe->abort) return EAGAIN; rc = hr_write_direct(extents[ext_idx].svc_id, io->ba, io->cnt, io->data_write); if (rc != EOK) io->vol->hr_ops.ext_state_cb(io->vol, io->extent, rc); return rc; } errno_t hr_io_raid5_noop_writer(void *arg) { hr_io_raid5_t *io = arg; hr_stripe_t *stripe = io->stripe; hr_stripe_commit_parity(stripe, io->strip_off, io->data_write, io->cnt * io->vol->bsize); return EOK; } errno_t hr_io_raid5_parity_getter(void *arg) { hr_io_raid5_t *io = arg; hr_stripe_t *stripe = io->stripe; size_t bsize = stripe->vol->bsize; hr_stripe_wait_for_parity_commits(stripe); if (stripe->abort) return EAGAIN; memcpy(io->data_read, stripe->parity + io->strip_off, io->cnt * bsize); return EOK; } errno_t hr_io_raid5_subtract_writer(void *arg) { errno_t rc; hr_io_raid5_t *io = arg; hr_stripe_t *stripe = io->stripe; size_t ext_idx = io->extent; hr_extent_t *extents = (hr_extent_t *)&io->vol->extents; uint8_t *data = hr_malloc_waitok(io->cnt * io->vol->bsize); rc = hr_read_direct(extents[ext_idx].svc_id, io->ba, io->cnt, data); if (rc != EOK) { io->vol->hr_ops.ext_state_cb(io->vol, io->extent, rc); hr_stripe_parity_abort(stripe); free(data); return rc; } fibril_mutex_lock(&stripe->parity_lock); hr_raid5_xor(stripe->parity + io->strip_off, data, io->cnt * io->vol->bsize); hr_raid5_xor(stripe->parity + io->strip_off, io->data_write, io->cnt * io->vol->bsize); stripe->ps_added++; fibril_condvar_broadcast(&stripe->ps_added_cv); fibril_mutex_unlock(&stripe->parity_lock); hr_stripe_wait_for_parity_commits(stripe); if (stripe->abort) return EAGAIN; rc = hr_write_direct(extents[ext_idx].svc_id, io->ba, io->cnt, io->data_write); if (rc != EOK) io->vol->hr_ops.ext_state_cb(io->vol, io->extent, rc); free(data); return rc; } errno_t hr_io_raid5_reconstruct_reader(void *arg) { errno_t rc; hr_io_raid5_t *io = arg; hr_stripe_t *stripe = io->stripe; size_t ext_idx = io->extent; hr_extent_t *extents = (hr_extent_t *)&io->vol->extents; uint8_t *data = hr_malloc_waitok(io->cnt * io->vol->bsize); rc = hr_read_direct(extents[ext_idx].svc_id, io->ba, io->cnt, data); if (rc != EOK) { hr_stripe_parity_abort(stripe); io->vol->hr_ops.ext_state_cb(io->vol, io->extent, rc); free(data); return rc; } hr_stripe_commit_parity(stripe, io->strip_off, data, io->cnt * io->vol->bsize); free(data); return EOK; } errno_t hr_io_raid5_parity_writer(void *arg) { errno_t rc; hr_io_raid5_t *io = arg; hr_stripe_t *stripe = io->stripe; hr_extent_t *extents = (hr_extent_t *)&io->vol->extents; hr_stripe_wait_for_parity_commits(stripe); if (stripe->abort) return EAGAIN; rc = hr_write_direct(extents[io->extent].svc_id, io->ba, io->cnt, stripe->parity + io->strip_off); if (rc != EOK) io->vol->hr_ops.ext_state_cb(io->vol, io->extent, rc); return rc; } /** @} */