From dd495c910297eac4ad5843e1fc7f19e79bbbcc6a Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Thu, 29 Aug 2024 19:56:11 +0200 Subject: [PATCH 001/324] locsrv: add "raid" category --- uspace/srv/locsrv/locsrv.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/uspace/srv/locsrv/locsrv.c b/uspace/srv/locsrv/locsrv.c index 16cc0cbcc6..22a4d6ff6d 100644 --- a/uspace/srv/locsrv/locsrv.c +++ b/uspace/srv/locsrv/locsrv.c @@ -1329,6 +1329,9 @@ static bool loc_init(void) cat = category_new("disk"); categ_dir_add_cat(&cdir, cat); + cat = category_new("raid"); + categ_dir_add_cat(&cdir, cat); + cat = category_new("partition"); categ_dir_add_cat(&cdir, cat); From 94d84a0030d010cf930ebf2405cb9d26c838699e Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Thu, 29 Aug 2024 21:03:45 +0200 Subject: [PATCH 002/324] hr: initial trivial mirroring implementation --- abi/include/abi/ipc/interfaces.h | 4 +- uspace/app/hrctl/hrctl.c | 229 ++++++++++++++++++++++++ uspace/app/hrctl/meson.build | 30 ++++ uspace/app/meson.build | 1 + uspace/lib/c/include/ipc/services.h | 1 + uspace/lib/device/include/hr.h | 70 ++++++++ uspace/lib/device/include/ipc/hr.h | 47 +++++ uspace/lib/device/meson.build | 1 + uspace/lib/device/src/hr.c | 127 +++++++++++++ uspace/srv/bd/hr/hr.c | 265 ++++++++++++++++++++++++++++ uspace/srv/bd/hr/meson.build | 30 ++++ uspace/srv/bd/hr/raid1.c | 207 ++++++++++++++++++++++ uspace/srv/bd/hr/var.h | 66 +++++++ uspace/srv/meson.build | 1 + 14 files changed, 1078 insertions(+), 1 deletion(-) create mode 100644 uspace/app/hrctl/hrctl.c create mode 100644 uspace/app/hrctl/meson.build create mode 100644 uspace/lib/device/include/hr.h create mode 100644 uspace/lib/device/include/ipc/hr.h create mode 100644 uspace/lib/device/src/hr.c create mode 100644 uspace/srv/bd/hr/hr.c create mode 100644 uspace/srv/bd/hr/meson.build create mode 100644 uspace/srv/bd/hr/raid1.c create mode 100644 uspace/srv/bd/hr/var.h diff --git a/abi/include/abi/ipc/interfaces.h b/abi/include/abi/ipc/interfaces.h index 54f05d19da..3f631e1461 100644 --- a/abi/include/abi/ipc/interfaces.h +++ b/abi/include/abi/ipc/interfaces.h @@ -201,7 +201,9 @@ typedef enum { INTERFACE_WNDMGT_CB = FOURCC_COMPACT('w', 'm', 'g', 't') | IFACE_EXCHANGE_SERIALIZE | IFACE_MOD_CALLBACK, INTERFACE_TBARCFG_NOTIFY = - FOURCC_COMPACT('t', 'b', 'c', 'f') | IFACE_EXCHANGE_SERIALIZE + FOURCC_COMPACT('t', 'b', 'c', 'f') | IFACE_EXCHANGE_SERIALIZE, + INTERFACE_HR = + FOURCC_COMPACT('h', 'r', ' ', ' ') | IFACE_EXCHANGE_SERIALIZE } iface_t; #endif diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c new file mode 100644 index 0000000000..9d48e0c445 --- /dev/null +++ b/uspace/app/hrctl/hrctl.c @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2024 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 hrctl + * @{ + */ +/** + * @file + */ + +#include +#include +#include +#include +#include +#include +#include + +static void usage(void); + +static const char usage_str[] = + "Usage: hrctl [OPTION]... -n ...\n" + "\n" + "Options:\n" + " -h, --help display this help and exit\n" + " -s, --status display status of active arrays\n" + " -a, --assemble=NAME assemble an existing array\n" + " -c, --create=NAME create new array\n" + " -n non-zero number of devices\n" + " -l, --level=LEVEL set the RAID level,\n" + " valid values: 0, 1, 5, linear\n" + " -0 striping\n" + " -1 mirroring\n" + " -5 distributed parity\n" + " -L linear concatenation\n" + "\n" + "Example usage:\n" + " hrctl --create /hr0 -0 -n 2 devices/\\hw\\0 devices/\\hw\\1\n" + " - creates new mirroring RAID device named /hr0 consisting\n" + " of 2 drives\n" + " hrctl --assemble /hr0 -n 2 devices/\\hw\\0 devices/\\hw\\1\n" + " - assembles RAID device named /hr0 consisting of 2 drives,\n" + " that were previously in an array\n"; + +static struct option const long_options[] = { + { "help", no_argument, 0, 'h' }, + { "status", no_argument, 0, 's' }, + { "assemble", required_argument, 0, 'a' }, + { "create", required_argument, 0, 'c' }, + { "level", required_argument, 0, 'l' }, + { 0, 0, 0, 0 } +}; + +static void usage(void) +{ + printf("%s", usage_str); +} + +static errno_t get_dev_svc_ids(int argc, char **argv, int optind, int dev_no, + service_id_t **rdevs) +{ + errno_t rc; + int i; + size_t k; + service_id_t *devs; + + devs = calloc(dev_no, sizeof(service_id_t)); + if (devs == NULL) + return ENOMEM; + + for (i = optind, k = 0; i < argc; i++, k++) { + rc = loc_service_get_id(argv[i], &devs[k], 0); + if (rc != EOK) { + printf("hrctl: error resolving device \"%s\"\n", argv[i]); + free(devs); + return EINVAL; + } + } + + *rdevs = devs; + + return EOK; +} + +int main(int argc, char **argv) +{ + errno_t rc; + int retval, c, dev_no; + bool create, assemble; + char *name = NULL; + service_id_t *devs = NULL; + hr_t *hr; + hr_config_t hr_config; + hr_level_t level; + + retval = 0; + level = hr_l_empty; + dev_no = 0; + create = assemble = false; + + if (argc < 2) { + goto bad; + } + + c = 0; + optreset = 1; + optind = 0; + + while (c != -1) { + c = getopt_long(argc, argv, "hsc:a:l:015Ln:", + long_options, NULL); + switch (c) { + case 'h': + usage(); + return 0; + case 's': + printf("hrctl: status not implemented yet\n"); + return 0; + case 'a': + name = optarg; + assemble = true; + break; + case 'c': + name = optarg; + create = true; + break; + case 'l': + if (level != hr_l_empty) + goto bad; + if (str_cmp(optarg, "linear") == 0) + level = hr_l_linear; + else + level = strtol(optarg, NULL, 10); + break; + case '0': + if (level != hr_l_empty) + goto bad; + level = hr_l_0; + break; + case '1': + if (level != hr_l_empty) + goto bad; + level = hr_l_1; + break; + case '5': + if (level != hr_l_empty) + goto bad; + level = hr_l_5; + break; + case 'L': + if (level != hr_l_empty) + goto bad; + level = hr_l_linear; + break; + case 'n': + dev_no = strtol(optarg, NULL, 10); + if (dev_no + optind != argc) + goto bad; + rc = get_dev_svc_ids(argc, argv, optind, dev_no, &devs); + if (rc != EOK) + return 1; + break; + } + } + + if ((create && assemble) || + (!create && !assemble) || + (create && level == hr_l_empty) || + (assemble && level != hr_l_empty) || + (dev_no == 0)) { + free(devs); + goto bad; + } + + hr_config.level = level; + hr_config.dev_no = dev_no; + hr_config.name = name; + hr_config.devs = devs; + + rc = hr_sess_init(&hr); + if (rc != EOK) { + printf("hrctl: hr_sess_init() rc: %s\n", str_error(rc)); + retval = 1; + goto end; + } + + if (create) { + rc = hr_create(hr, &hr_config); + printf("hrctl: hr_create() rc: %s\n", str_error(rc)); + } else if (assemble) { + printf("hrctl: assemble not implemented yet\n"); + } + +end: + free(devs); + hr_sess_destroy(hr); + return retval; +bad: + printf("hrctl: bad usage, try hrctl --help\n"); + return 1; +} + +/** @} + */ diff --git a/uspace/app/hrctl/meson.build b/uspace/app/hrctl/meson.build new file mode 100644 index 0000000000..84d2fa1eb0 --- /dev/null +++ b/uspace/app/hrctl/meson.build @@ -0,0 +1,30 @@ +# +# Copyright (c) 2024 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. +# + +deps = [ 'device' ] +src = files('hrctl.c') diff --git a/uspace/app/meson.build b/uspace/app/meson.build index aa5c9a59f9..51f22e8f0b 100644 --- a/uspace/app/meson.build +++ b/uspace/app/meson.build @@ -51,6 +51,7 @@ apps = [ 'gunzip', 'hbench', 'hello', + 'hrctl', 'inet', 'init', 'kill', diff --git a/uspace/lib/c/include/ipc/services.h b/uspace/lib/c/include/ipc/services.h index 34ed1531f1..fcb1ee222d 100644 --- a/uspace/lib/c/include/ipc/services.h +++ b/uspace/lib/c/include/ipc/services.h @@ -57,6 +57,7 @@ typedef enum { #define SERVICE_NAME_DISPCFG "hid/display" #define SERVICE_NAME_DISPLAY "hid/display" #define SERVICE_NAME_WNDMGT "hid/display" +#define SERVICE_NAME_HR "hr" #define SERVICE_NAME_DHCP "net/dhcp" #define SERVICE_NAME_DNSR "net/dnsr" #define SERVICE_NAME_INET "net/inet" diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h new file mode 100644 index 0000000000..4b558dfb3e --- /dev/null +++ b/uspace/lib/device/include/hr.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2024 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 libdevice + * @{ + */ +/** + * @file + */ + +#ifndef LIBDEVICE_HR_H +#define LIBDEVICE_HR_H + +#include +#include +#include + +typedef struct hr { + async_sess_t *sess; +} hr_t; + +typedef enum hr_level { + hr_l_0 = 0, + hr_l_1 = 1, + hr_l_5 = 5, + hr_l_linear = 254, + hr_l_empty = 255 +} hr_level_t; + +typedef struct hr_config { + char *name; + service_id_t *devs; + size_t dev_no; + hr_level_t level; +} hr_config_t; + +extern errno_t hr_sess_init(hr_t **); +extern void hr_sess_destroy(hr_t *); + +extern errno_t hr_create(hr_t *, hr_config_t *); + +#endif + +/** @} + */ diff --git a/uspace/lib/device/include/ipc/hr.h b/uspace/lib/device/include/ipc/hr.h new file mode 100644 index 0000000000..3effc98452 --- /dev/null +++ b/uspace/lib/device/include/ipc/hr.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024 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 libdevice + * @{ + */ +/** @file + */ + +#ifndef LIBDEVICE_IPC_HR_H +#define LIBDEVICE_IPC_HR_H + +#include + +typedef enum { + HR_CREATE = IPC_FIRST_USER_METHOD +} hr_request_t; + +#endif + +/** @} + */ diff --git a/uspace/lib/device/meson.build b/uspace/lib/device/meson.build index ed7659953c..e6ee1a7e33 100644 --- a/uspace/lib/device/meson.build +++ b/uspace/lib/device/meson.build @@ -31,6 +31,7 @@ src = files( 'src/bd_srv.c', 'src/devman.c', 'src/device/led_dev.c', + 'src/hr.c', 'src/io/chardev.c', 'src/io/chardev_srv.c', 'src/io/label.c', diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c new file mode 100644 index 0000000000..6f9b90be78 --- /dev/null +++ b/uspace/lib/device/src/hr.c @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2024 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 libdevice + * @{ + */ +/** + * @file + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +errno_t hr_sess_init(hr_t **rhr) +{ + errno_t rc; + + hr_t *hr = calloc(1, sizeof(hr_t)); + if (hr == NULL) { + rc = ENOMEM; + goto error; + } + + service_id_t hr_svcid; + + rc = loc_service_get_id(SERVICE_NAME_HR, &hr_svcid, IPC_FLAG_BLOCKING); + if (rc != EOK) { + rc = EIO; + goto error; + } + + hr->sess = loc_service_connect(hr_svcid, INTERFACE_HR, + IPC_FLAG_BLOCKING); + if (hr->sess == NULL) { + rc = EIO; + goto error; + } + + *rhr = hr; + return EOK; +error: + if (hr != NULL) + free(hr); + *rhr = NULL; + return rc; +} + +void hr_sess_destroy(hr_t *hr) +{ + if (hr == NULL) + return; + + async_hangup(hr->sess); + free(hr); +} + +errno_t hr_create(hr_t *hr, hr_config_t *hr_config) +{ + errno_t rc, retval; + async_exch_t *exch; + aid_t req; + + exch = async_exchange_begin(hr->sess); + if (exch == NULL) { + return EINVAL; + } + + req = async_send_1(exch, HR_CREATE, hr_config->level, NULL); + + rc = async_data_write_start(exch, hr_config->name, + str_size(hr_config->name)); + if (rc != EOK) { + async_exchange_end(exch); + async_forget(req); + return rc; + } + + rc = async_data_write_start(exch, hr_config->devs, + sizeof(service_id_t) * hr_config->dev_no); + if (rc != EOK) { + async_exchange_end(exch); + async_forget(req); + return rc; + } + + async_exchange_end(exch); + async_wait_for(req, &retval); + if (retval != EOK) + return retval; + + return EOK; +} + +/** @} + */ diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c new file mode 100644 index 0000000000..e50918e6d5 --- /dev/null +++ b/uspace/srv/bd/hr/hr.c @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2024 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 +#include +#include +#include +#include +#include + +#include "var.h" + +loc_srv_t *hr_srv; +fibril_mutex_t big_lock; /* for now */ + +static fibril_mutex_t hr_volumes_lock; +static list_t hr_volumes; + +static service_id_t ctl_sid; + +errno_t hr_init_devs(hr_volume_t *vol) +{ + log_msg(LOG_DEFAULT, LVL_NOTE, "hr_init_devs()"); + + errno_t rc; + size_t i; + + for (i = 0; i < vol->dev_no; i++) { + rc = block_init(vol->devs[i]); + log_msg(LOG_DEFAULT, LVL_DEBUG, + "hr_init_devs(): initing (%" PRIun ")", vol->devs[i]); + if (rc != EOK) { + log_msg(LOG_DEFAULT, LVL_ERROR, + "hr_init_devs(): initing (%" PRIun ") failed, aborting", + vol->devs[i]); + break; + } + } + + return rc; +} + +void hr_fini_devs(hr_volume_t *vol) +{ + log_msg(LOG_DEFAULT, LVL_NOTE, "hr_fini_devs()"); + + size_t i; + + for (i = 0; i < vol->dev_no; i++) + block_fini(vol->devs[i]); +} + +static void hr_create_srv(ipc_call_t *icall) +{ + log_msg(LOG_DEFAULT, LVL_NOTE, "hr_create_srv()"); + + errno_t rc; + size_t size; + hr_config_t *hr_config; + + hr_config = calloc(1, sizeof(hr_config_t)); + if (hr_config == NULL) { + async_answer_0(icall, ENOMEM); + return; + } + + hr_config->level = ipc_get_arg1(icall); + + rc = async_data_write_accept((void **) &hr_config->name, true, 0, 0, 0, + NULL); + if (rc != EOK) { + async_answer_0(icall, EREFUSED); + return; + } + + rc = async_data_write_accept((void **) &hr_config->devs, false, + sizeof(service_id_t), 0, 0, &size); + if (rc != EOK) { + async_answer_0(icall, EREFUSED); + return; + } + + hr_config->dev_no = size / sizeof(service_id_t); + + fibril_mutex_initialize(&big_lock); + + hr_volume_t *new_volume = calloc(1, sizeof(hr_volume_t)); + if (new_volume == NULL) { + rc = ENOMEM; + goto end; + } + new_volume->devname = hr_config->name; + new_volume->level = hr_config->level; + new_volume->dev_no = hr_config->dev_no; + new_volume->devs = hr_config->devs; + + switch (hr_config->level) { + case hr_l_1: + new_volume->hr_ops.create = hr_raid1_create; + break; + default: + log_msg(LOG_DEFAULT, LVL_NOTE, + "level %d not implemented yet\n", new_volume->level); + rc = EINVAL; + goto end; + } + + rc = new_volume->hr_ops.create(new_volume); + if (rc != EOK) + goto end; + + fibril_mutex_lock(&hr_volumes_lock); + list_append(&new_volume->lvolumes, &hr_volumes); + fibril_mutex_unlock(&hr_volumes_lock); + + log_msg(LOG_DEFAULT, LVL_NOTE, "created volume \"%s\" (%" PRIun ")\n", + new_volume->devname, new_volume->svc_id); + +end: + free(hr_config); + async_answer_0(icall, rc); +} + +static void hr_ctl_conn(ipc_call_t *icall, void *arg) +{ + log_msg(LOG_DEFAULT, LVL_NOTE, "hr_ctl_conn()"); + + async_accept_0(icall); + + while (true) { + ipc_call_t call; + async_get_call(&call); + sysarg_t method = ipc_get_imethod(&call); + + if (!method) { + async_answer_0(&call, EOK); + return; + } + + switch (method) { + case HR_CREATE: + hr_create_srv(&call); + break; + default: + async_answer_0(&call, EINVAL); + } + } +} + +static hr_volume_t *hr_get_volume(service_id_t svc_id) +{ + log_msg(LOG_DEFAULT, LVL_DEBUG, "hr_get_volume(): (%" PRIun ")", + svc_id); + + fibril_mutex_lock(&hr_volumes_lock); + list_foreach(hr_volumes, lvolumes, hr_volume_t, volume) { + if (volume->svc_id == svc_id) { + fibril_mutex_unlock(&hr_volumes_lock); + return volume; + } + } + + fibril_mutex_lock(&hr_volumes_lock); + return NULL; +} + +static void hr_client_conn(ipc_call_t *icall, void *arg) +{ + log_msg(LOG_DEFAULT, LVL_NOTE, "hr_client_conn()"); + + hr_volume_t *vol; + + sysarg_t svc_id = ipc_get_arg2(icall); + + if (svc_id == ctl_sid) { + hr_ctl_conn(icall, arg); + } else { + log_msg(LOG_DEFAULT, LVL_NOTE, "bd_conn()"); + vol = hr_get_volume(svc_id); + if (vol == NULL) + async_answer_0(icall, EINVAL); + bd_conn(icall, &vol->hr_bds); + } +} + +int main(int argc, char **argv) +{ + errno_t rc; + + printf("%s: HelenRAID server\n", NAME); + + rc = log_init(NAME); + if (rc != EOK) { + printf("%s: failed to initialize logging\n", NAME); + return 1; + } + + fibril_mutex_initialize(&hr_volumes_lock); + list_initialize(&hr_volumes); + + async_set_fallback_port_handler(hr_client_conn, NULL); + + rc = loc_server_register(NAME, &hr_srv); + if (rc != EOK) { + log_msg(LOG_DEFAULT, LVL_ERROR, + "failed registering server: %s", str_error(rc)); + return EEXIST; + } + + rc = loc_service_register(hr_srv, SERVICE_NAME_HR, &ctl_sid); + if (rc != EOK) { + log_msg(LOG_DEFAULT, LVL_ERROR, + "failed registering service: %s", str_error(rc)); + return EEXIST; + } + + printf("%s: accepting connections\n", NAME); + task_retval(0); + async_manager(); + + return 0; +} + +/** @} + */ diff --git a/uspace/srv/bd/hr/meson.build b/uspace/srv/bd/hr/meson.build new file mode 100644 index 0000000000..5fde8f02c9 --- /dev/null +++ b/uspace/srv/bd/hr/meson.build @@ -0,0 +1,30 @@ +# +# Copyright (c) 2024 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. +# + +deps = [ 'block', 'device' ] +src = files('hr.c', 'raid1.c') diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c new file mode 100644 index 0000000000..c25fe6ed21 --- /dev/null +++ b/uspace/srv/bd/hr/raid1.c @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2024 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 +#include +#include +#include +#include + +#include "var.h" + +extern fibril_mutex_t big_lock; +extern loc_srv_t *hr_srv; + +static errno_t hr_raid1_bd_open(bd_srvs_t *, bd_srv_t *); +static errno_t hr_raid1_bd_close(bd_srv_t *); +static errno_t hr_raid1_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, + size_t); +static errno_t hr_raid1_bd_sync_cache(bd_srv_t *, aoff64_t, size_t); +static errno_t hr_raid1_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, + const void *, size_t); +static errno_t hr_raid1_bd_get_block_size(bd_srv_t *, size_t *); +static errno_t hr_raid1_bd_get_num_blocks(bd_srv_t *, aoff64_t *); + +static bd_ops_t hr_raid1_bd_ops = { + .open = hr_raid1_bd_open, + .close = hr_raid1_bd_close, + .sync_cache = hr_raid1_bd_sync_cache, + .read_blocks = hr_raid1_bd_read_blocks, + .write_blocks = hr_raid1_bd_write_blocks, + .get_block_size = hr_raid1_bd_get_block_size, + .get_num_blocks = hr_raid1_bd_get_num_blocks +}; + +static errno_t hr_raid1_bd_open(bd_srvs_t *bds, bd_srv_t *bd) +{ + log_msg(LOG_DEFAULT, LVL_NOTE, "hr_bd_open()"); + return EOK; +} + +static errno_t hr_raid1_bd_close(bd_srv_t *bd) +{ + log_msg(LOG_DEFAULT, LVL_NOTE, "hr_bd_close()"); + return EOK; +} + +static errno_t hr_raid1_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t size) +{ + fibril_mutex_lock(&big_lock); + hr_volume_t *vol = bd->srvs->sarg; + + errno_t rc; + size_t i; + + for (i = 0; i < vol->dev_no; i++) { + rc = block_sync_cache(vol->devs[i], ba, size); + if (rc != EOK) + break; + } + + fibril_mutex_unlock(&big_lock); + return rc; +} + +static errno_t hr_raid1_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, + void *buf, size_t size) +{ + fibril_mutex_lock(&big_lock); + hr_volume_t *vol = bd->srvs->sarg; + + errno_t rc; + size_t i; + + for (i = 0; i < vol->dev_no; i++) { + rc = block_read_direct(vol->devs[i], ba, cnt, buf); + if (rc != EOK) + break; + } + + fibril_mutex_unlock(&big_lock); + return rc; +} + +static errno_t hr_raid1_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, + const void *data, size_t size) +{ + fibril_mutex_lock(&big_lock); + hr_volume_t *vol = bd->srvs->sarg; + + errno_t rc; + size_t i; + + for (i = 0; i < vol->dev_no; i++) { + rc = block_write_direct(vol->devs[i], ba, cnt, data); + if (rc != EOK) + break; + } + + fibril_mutex_unlock(&big_lock); + return rc; +} + +static errno_t hr_raid1_bd_get_block_size(bd_srv_t *bd, size_t *rsize) +{ + hr_volume_t *vol = bd->srvs->sarg; + + return block_get_bsize(vol->devs[0], rsize); +} + +static errno_t hr_raid1_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb) +{ + hr_volume_t *vol = bd->srvs->sarg; + + return block_get_nblocks(vol->devs[0], rnb); +} + +errno_t hr_raid1_create(hr_volume_t *new_volume) +{ + assert(new_volume->level == hr_l_1); + + errno_t rc; + service_id_t new_id; + category_id_t cat_id; + + rc = hr_init_devs(new_volume); + if (rc != EOK) + goto end; + + bd_srvs_init(&new_volume->hr_bds); + new_volume->hr_bds.ops = &hr_raid1_bd_ops; + new_volume->hr_bds.sarg = new_volume; + + rc = loc_service_register(hr_srv, new_volume->devname, &new_id); + if (rc != EOK) { + log_msg(LOG_DEFAULT, LVL_ERROR, + "unable to register device \"%s\": %s\n", + new_volume->devname, str_error(rc)); + + goto error; + } + + rc = loc_category_get_id("raid", &cat_id, IPC_FLAG_BLOCKING); + if (rc != EOK) { + log_msg(LOG_DEFAULT, LVL_ERROR, + "failed resolving category \"raid\": %s\n", str_error(rc)); + goto error; + } + + rc = loc_service_add_to_cat(hr_srv, new_id, cat_id); + if (rc != EOK) { + log_msg(LOG_DEFAULT, LVL_ERROR, + "failed adding \"%s\" to category \"raid\": %s\n", + new_volume->devname, str_error(rc)); + goto error; + } + + new_volume->svc_id = new_id; + + return EOK; +error: + hr_fini_devs(new_volume); +end: + return rc; +} + +/** @} + */ diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h new file mode 100644 index 0000000000..23eedca73c --- /dev/null +++ b/uspace/srv/bd/hr/var.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2024 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 + */ + +#ifndef _HR_VAR_H +#define _HR_VAR_H + +#define NAME "hr" + +typedef struct hr_volume hr_volume_t; + +typedef struct hr_ops { + errno_t (*create)(hr_volume_t *); +} hr_ops_t; + +typedef struct hr_volume { + hr_ops_t hr_ops; + bd_srvs_t hr_bds; + link_t lvolumes; + char *devname; + service_id_t *devs; + service_id_t svc_id; + size_t dev_no; + hr_level_t level; +} hr_volume_t; + +extern errno_t hr_init_devs(hr_volume_t *); +extern void hr_fini_devs(hr_volume_t *); + +extern errno_t hr_raid1_create(hr_volume_t *); + +#endif + +/** @} + */ diff --git a/uspace/srv/meson.build b/uspace/srv/meson.build index 4536385a2b..12a46c66cd 100644 --- a/uspace/srv/meson.build +++ b/uspace/srv/meson.build @@ -29,6 +29,7 @@ srvs = [ 'audio/hound', 'bd/file_bd', + 'bd/hr', 'bd/rd', 'bd/sata_bd', 'bd/vbd', From 4e841766a5651fa1e08e75de7ce1bdfde08bdc42 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Thu, 29 Aug 2024 21:08:10 +0200 Subject: [PATCH 003/324] init: add "/srv/bd/hr" --- uspace/app/init/init.c | 1 + 1 file changed, 1 insertion(+) diff --git a/uspace/app/init/init.c b/uspace/app/init/init.c index 6cd418facc..dabe892058 100644 --- a/uspace/app/init/init.c +++ b/uspace/app/init/init.c @@ -500,6 +500,7 @@ int main(int argc, char *argv[]) srv_start("/srv/hid/s3c24xx_ts"); srv_start("/srv/bd/vbd"); + srv_start("/srv/bd/hr"); srv_start("/srv/volsrv"); init_sysvol(); From e0b77635017006b1dfe6a20ca68c086548186884 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 30 Aug 2024 16:49:23 +0200 Subject: [PATCH 004/324] hr: fix volume list locking --- uspace/srv/bd/hr/hr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index e50918e6d5..b9de456250 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -200,7 +200,7 @@ static hr_volume_t *hr_get_volume(service_id_t svc_id) } } - fibril_mutex_lock(&hr_volumes_lock); + fibril_mutex_unlock(&hr_volumes_lock); return NULL; } From da5c2573ab7873f71a08944e3ac7c0fe455eb6bd Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sat, 31 Aug 2024 12:35:43 +0200 Subject: [PATCH 005/324] hr: create util.c --- uspace/srv/bd/hr/hr.c | 35 +---------- uspace/srv/bd/hr/meson.build | 2 +- uspace/srv/bd/hr/raid1.c | 35 ++--------- uspace/srv/bd/hr/util.c | 116 +++++++++++++++++++++++++++++++++++ uspace/srv/bd/hr/util.h | 50 +++++++++++++++ uspace/srv/bd/hr/var.h | 5 ++ 6 files changed, 178 insertions(+), 65 deletions(-) create mode 100644 uspace/srv/bd/hr/util.c create mode 100644 uspace/srv/bd/hr/util.h diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index b9de456250..82c885352a 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -35,7 +35,6 @@ #include #include -#include #include #include #include @@ -58,38 +57,6 @@ static list_t hr_volumes; static service_id_t ctl_sid; -errno_t hr_init_devs(hr_volume_t *vol) -{ - log_msg(LOG_DEFAULT, LVL_NOTE, "hr_init_devs()"); - - errno_t rc; - size_t i; - - for (i = 0; i < vol->dev_no; i++) { - rc = block_init(vol->devs[i]); - log_msg(LOG_DEFAULT, LVL_DEBUG, - "hr_init_devs(): initing (%" PRIun ")", vol->devs[i]); - if (rc != EOK) { - log_msg(LOG_DEFAULT, LVL_ERROR, - "hr_init_devs(): initing (%" PRIun ") failed, aborting", - vol->devs[i]); - break; - } - } - - return rc; -} - -void hr_fini_devs(hr_volume_t *vol) -{ - log_msg(LOG_DEFAULT, LVL_NOTE, "hr_fini_devs()"); - - size_t i; - - for (i = 0; i < vol->dev_no; i++) - block_fini(vol->devs[i]); -} - static void hr_create_srv(ipc_call_t *icall) { log_msg(LOG_DEFAULT, LVL_NOTE, "hr_create_srv()"); @@ -210,7 +177,7 @@ static void hr_client_conn(ipc_call_t *icall, void *arg) hr_volume_t *vol; - sysarg_t svc_id = ipc_get_arg2(icall); + service_id_t svc_id = ipc_get_arg2(icall); if (svc_id == ctl_sid) { hr_ctl_conn(icall, arg); diff --git a/uspace/srv/bd/hr/meson.build b/uspace/srv/bd/hr/meson.build index 5fde8f02c9..6e05632058 100644 --- a/uspace/srv/bd/hr/meson.build +++ b/uspace/srv/bd/hr/meson.build @@ -27,4 +27,4 @@ # deps = [ 'block', 'device' ] -src = files('hr.c', 'raid1.c') +src = files('hr.c', 'raid1.c', 'util.c') diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index c25fe6ed21..bd612f3ff8 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -48,6 +48,7 @@ #include #include "var.h" +#include "util.h" extern fibril_mutex_t big_lock; extern loc_srv_t *hr_srv; @@ -159,48 +160,22 @@ errno_t hr_raid1_create(hr_volume_t *new_volume) assert(new_volume->level == hr_l_1); errno_t rc; - service_id_t new_id; - category_id_t cat_id; rc = hr_init_devs(new_volume); if (rc != EOK) - goto end; + return rc; bd_srvs_init(&new_volume->hr_bds); new_volume->hr_bds.ops = &hr_raid1_bd_ops; new_volume->hr_bds.sarg = new_volume; - rc = loc_service_register(hr_srv, new_volume->devname, &new_id); + rc = hr_register_volume(new_volume); if (rc != EOK) { - log_msg(LOG_DEFAULT, LVL_ERROR, - "unable to register device \"%s\": %s\n", - new_volume->devname, str_error(rc)); - - goto error; + hr_fini_devs(new_volume); + return rc; } - rc = loc_category_get_id("raid", &cat_id, IPC_FLAG_BLOCKING); - if (rc != EOK) { - log_msg(LOG_DEFAULT, LVL_ERROR, - "failed resolving category \"raid\": %s\n", str_error(rc)); - goto error; - } - - rc = loc_service_add_to_cat(hr_srv, new_id, cat_id); - if (rc != EOK) { - log_msg(LOG_DEFAULT, LVL_ERROR, - "failed adding \"%s\" to category \"raid\": %s\n", - new_volume->devname, str_error(rc)); - goto error; - } - - new_volume->svc_id = new_id; - return EOK; -error: - hr_fini_devs(new_volume); -end: - return rc; } /** @} diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c new file mode 100644 index 0000000000..72f34bf119 --- /dev/null +++ b/uspace/srv/bd/hr/util.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2024 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 "var.h" +#include "util.h" + +extern loc_srv_t *hr_srv; + +errno_t hr_init_devs(hr_volume_t *vol) +{ + log_msg(LOG_DEFAULT, LVL_NOTE, "hr_init_devs()"); + + errno_t rc; + size_t i; + + for (i = 0; i < vol->dev_no; i++) { + rc = block_init(vol->devs[i]); + log_msg(LOG_DEFAULT, LVL_DEBUG, + "hr_init_devs(): initing (%" PRIun ")", vol->devs[i]); + if (rc != EOK) { + log_msg(LOG_DEFAULT, LVL_ERROR, + "hr_init_devs(): initing (%" PRIun ") failed, aborting", + vol->devs[i]); + break; + } + } + + return rc; +} + +void hr_fini_devs(hr_volume_t *vol) +{ + log_msg(LOG_DEFAULT, LVL_NOTE, "hr_fini_devs()"); + + size_t i; + + for (i = 0; i < vol->dev_no; i++) + block_fini(vol->devs[i]); +} + +errno_t hr_register_volume(hr_volume_t *new_volume) +{ + errno_t rc; + service_id_t new_id; + category_id_t cat_id; + + rc = loc_service_register(hr_srv, new_volume->devname, &new_id); + if (rc != EOK) { + log_msg(LOG_DEFAULT, LVL_ERROR, + "unable to register device \"%s\": %s\n", + new_volume->devname, str_error(rc)); + goto error; + } + + rc = loc_category_get_id("raid", &cat_id, IPC_FLAG_BLOCKING); + if (rc != EOK) { + log_msg(LOG_DEFAULT, LVL_ERROR, + "failed resolving category \"raid\": %s\n", str_error(rc)); + goto error; + } + + rc = loc_service_add_to_cat(hr_srv, new_id, cat_id); + if (rc != EOK) { + log_msg(LOG_DEFAULT, LVL_ERROR, + "failed adding \"%s\" to category \"raid\": %s\n", + new_volume->devname, str_error(rc)); + goto error; + } + + new_volume->svc_id = new_id; + +error: + return rc; +} + +/** @} + */ diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h new file mode 100644 index 0000000000..3635371639 --- /dev/null +++ b/uspace/srv/bd/hr/util.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2024 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 + */ + +#ifndef _HR_UTIL_H +#define _HR_UTIL_H + +#include + +#include "var.h" + +extern errno_t hr_init_devs(hr_volume_t *); +extern void hr_fini_devs(hr_volume_t *); +extern errno_t hr_register_volume(hr_volume_t *); + +#endif + +/** @} + */ diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index 23eedca73c..690b679efd 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -36,6 +36,10 @@ #ifndef _HR_VAR_H #define _HR_VAR_H +#include +#include +#include + #define NAME "hr" typedef struct hr_volume hr_volume_t; @@ -58,6 +62,7 @@ typedef struct hr_volume { extern errno_t hr_init_devs(hr_volume_t *); extern void hr_fini_devs(hr_volume_t *); +extern errno_t hr_raid0_create(hr_volume_t *); extern errno_t hr_raid1_create(hr_volume_t *); #endif From 12cbf25eb6600e54e4225574fff10dbd9b607c16 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sat, 31 Aug 2024 15:09:16 +0200 Subject: [PATCH 006/324] hr: disk size checking --- uspace/srv/bd/hr/raid1.c | 53 ++++++++++++++++++++++++++++++++++------ uspace/srv/bd/hr/var.h | 2 ++ 2 files changed, 48 insertions(+), 7 deletions(-) diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index bd612f3ff8..39ed7c98b6 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -33,7 +33,6 @@ * @file */ -#include #include #include #include @@ -145,37 +144,77 @@ static errno_t hr_raid1_bd_get_block_size(bd_srv_t *bd, size_t *rsize) { hr_volume_t *vol = bd->srvs->sarg; - return block_get_bsize(vol->devs[0], rsize); + *rsize = vol->bsize; + return EOK; } static errno_t hr_raid1_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb) { hr_volume_t *vol = bd->srvs->sarg; - return block_get_nblocks(vol->devs[0], rnb); + *rnb = vol->nblocks; + return EOK; } errno_t hr_raid1_create(hr_volume_t *new_volume) { assert(new_volume->level == hr_l_1); + if (new_volume->dev_no < 2) { + log_msg(LOG_DEFAULT, LVL_ERROR, + "RAID 1 array needs at least 2 devices"); + return EINVAL; + } + errno_t rc; + size_t i, bsize, last_bsize; + uint64_t nblocks, last_nblocks; + uint64_t total_blocks = 0; rc = hr_init_devs(new_volume); if (rc != EOK) return rc; + for (i = 0; i < new_volume->dev_no; i++) { + rc = block_get_nblocks(new_volume->devs[i], &nblocks); + if (rc != EOK) + goto error; + if (i != 0 && nblocks != last_nblocks) { + log_msg(LOG_DEFAULT, LVL_ERROR, + "number of blocks differs"); + rc = EINVAL; + goto error; + } + total_blocks += nblocks; + last_nblocks = nblocks; + } + + for (i = 0; i < new_volume->dev_no; i++) { + rc = block_get_bsize(new_volume->devs[i], &bsize); + if (rc != EOK) + goto error; + if (i != 0 && bsize != last_bsize) { + log_msg(LOG_DEFAULT, LVL_ERROR, "block sizes differ"); + rc = EINVAL; + goto error; + } + last_bsize = bsize; + } + bd_srvs_init(&new_volume->hr_bds); new_volume->hr_bds.ops = &hr_raid1_bd_ops; new_volume->hr_bds.sarg = new_volume; + new_volume->nblocks = total_blocks / new_volume->dev_no; + new_volume->bsize = bsize; rc = hr_register_volume(new_volume); - if (rc != EOK) { - hr_fini_devs(new_volume); - return rc; - } + if (rc != EOK) + goto error; return EOK; +error: + hr_fini_devs(new_volume); + return rc; } /** @} diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index 690b679efd..246895df8c 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -54,6 +54,8 @@ typedef struct hr_volume { link_t lvolumes; char *devname; service_id_t *devs; + uint64_t nblocks; + size_t bsize; service_id_t svc_id; size_t dev_no; hr_level_t level; From a8b2d9e78af776b5f808152d8e4407605d111142 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sat, 31 Aug 2024 15:26:41 +0200 Subject: [PATCH 007/324] hr: add RAID 0 (striping) --- uspace/srv/bd/hr/hr.c | 3 + uspace/srv/bd/hr/meson.build | 2 +- uspace/srv/bd/hr/raid0.c | 258 +++++++++++++++++++++++++++++++++++ 3 files changed, 262 insertions(+), 1 deletion(-) create mode 100644 uspace/srv/bd/hr/raid0.c diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 82c885352a..e2bce0198e 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -105,6 +105,9 @@ static void hr_create_srv(ipc_call_t *icall) case hr_l_1: new_volume->hr_ops.create = hr_raid1_create; break; + case hr_l_0: + new_volume->hr_ops.create = hr_raid0_create; + break; default: log_msg(LOG_DEFAULT, LVL_NOTE, "level %d not implemented yet\n", new_volume->level); diff --git a/uspace/srv/bd/hr/meson.build b/uspace/srv/bd/hr/meson.build index 6e05632058..ee66fa6e03 100644 --- a/uspace/srv/bd/hr/meson.build +++ b/uspace/srv/bd/hr/meson.build @@ -27,4 +27,4 @@ # deps = [ 'block', 'device' ] -src = files('hr.c', 'raid1.c', 'util.c') +src = files('hr.c', 'raid0.c', 'raid1.c', 'util.c') diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c new file mode 100644 index 0000000000..2f1075a2dc --- /dev/null +++ b/uspace/srv/bd/hr/raid0.c @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2024 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 +#include +#include +#include +#include + +#include "var.h" +#include "util.h" + +extern fibril_mutex_t big_lock; +extern loc_srv_t *hr_srv; + +static errno_t hr_raid0_bd_open(bd_srvs_t *, bd_srv_t *); +static errno_t hr_raid0_bd_close(bd_srv_t *); +static errno_t hr_raid0_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, + size_t); +static errno_t hr_raid0_bd_sync_cache(bd_srv_t *, aoff64_t, size_t); +static errno_t hr_raid0_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, + const void *, size_t); +static errno_t hr_raid0_bd_get_block_size(bd_srv_t *, size_t *); +static errno_t hr_raid0_bd_get_num_blocks(bd_srv_t *, aoff64_t *); + +#define strip_size DATA_XFER_LIMIT + +static bd_ops_t hr_raid0_bd_ops = { + .open = hr_raid0_bd_open, + .close = hr_raid0_bd_close, + .sync_cache = hr_raid0_bd_sync_cache, + .read_blocks = hr_raid0_bd_read_blocks, + .write_blocks = hr_raid0_bd_write_blocks, + .get_block_size = hr_raid0_bd_get_block_size, + .get_num_blocks = hr_raid0_bd_get_num_blocks +}; + +static void raid0_geometry(uint64_t x, hr_volume_t *vol, size_t *extent, + uint64_t *phys_block) +{ + uint64_t N = vol->dev_no; /* extents */ + uint64_t L = strip_size / vol->bsize; /* size of strip in blocks */ + + uint64_t i = (x / L) % N; /* extent */ + uint64_t j = (x / L) / N; /* stripe */ + uint64_t k = x % L; /* strip offset */ + + *extent = i; + *phys_block = j * L + k; +} + +static errno_t hr_raid0_bd_open(bd_srvs_t *bds, bd_srv_t *bd) +{ + log_msg(LOG_DEFAULT, LVL_NOTE, "hr_bd_open()"); + return EOK; +} + +static errno_t hr_raid0_bd_close(bd_srv_t *bd) +{ + log_msg(LOG_DEFAULT, LVL_NOTE, "hr_bd_close()"); + return EOK; +} + +static errno_t hr_raid0_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) +{ + hr_volume_t *vol = bd->srvs->sarg; + errno_t rc; + uint64_t phys_block; + size_t extent; + + fibril_mutex_lock(&big_lock); + + size_t left = cnt; + while (left != 0) { + raid0_geometry(ba++, vol, &extent, &phys_block); + rc = block_sync_cache(vol->devs[extent], phys_block, 1); + if (rc != EOK) + break; + left--; + } + + fibril_mutex_unlock(&big_lock); + return rc; +} + +static errno_t hr_raid0_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, + void *buf, size_t size) +{ + hr_volume_t *vol = bd->srvs->sarg; + errno_t rc; + uint64_t phys_block; + size_t extent; + + if (size < cnt * vol->bsize) + return EINVAL; + + fibril_mutex_lock(&big_lock); + + size_t left = cnt; + while (left != 0) { + raid0_geometry(ba++, vol, &extent, &phys_block); + rc = block_read_direct(vol->devs[extent], phys_block, 1, buf); + buf = buf + vol->bsize; + if (rc != EOK) + break; + left--; + } + + fibril_mutex_unlock(&big_lock); + return rc; +} + +static errno_t hr_raid0_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, + const void *data, size_t size) +{ + hr_volume_t *vol = bd->srvs->sarg; + errno_t rc; + uint64_t phys_block; + size_t extent; + + if (size < cnt * vol->bsize) + return EINVAL; + + fibril_mutex_lock(&big_lock); + + size_t left = cnt; + while (left != 0) { + raid0_geometry(ba++, vol, &extent, &phys_block); + rc = block_write_direct(vol->devs[extent], phys_block, 1, data); + data = data + vol->bsize; + if (rc != EOK) + break; + left--; + } + + fibril_mutex_unlock(&big_lock); + return rc; +} + +static errno_t hr_raid0_bd_get_block_size(bd_srv_t *bd, size_t *rsize) +{ + hr_volume_t *vol = bd->srvs->sarg; + + *rsize = vol->bsize; + return EOK; +} + +static errno_t hr_raid0_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb) +{ + hr_volume_t *vol = bd->srvs->sarg; + + *rnb = vol->nblocks; + return EOK; +} + +errno_t hr_raid0_create(hr_volume_t *new_volume) +{ + assert(new_volume->level == hr_l_0); + + if (new_volume->dev_no < 2) { + log_msg(LOG_DEFAULT, LVL_ERROR, + "RAID 0 array needs at least 2 devices"); + return EINVAL; + } + + errno_t rc; + size_t i, bsize, last_bsize; + uint64_t nblocks, last_nblocks; + uint64_t total_blocks = 0; + + rc = hr_init_devs(new_volume); + if (rc != EOK) + return rc; + + for (i = 0; i < new_volume->dev_no; i++) { + rc = block_get_nblocks(new_volume->devs[i], &nblocks); + if (rc != EOK) + goto error; + if (i != 0 && nblocks != last_nblocks) { + log_msg(LOG_DEFAULT, LVL_ERROR, + "number of blocks differs"); + rc = EINVAL; + goto error; + } + total_blocks += nblocks; + last_nblocks = nblocks; + } + + for (i = 0; i < new_volume->dev_no; i++) { + rc = block_get_bsize(new_volume->devs[i], &bsize); + if (rc != EOK) + goto error; + if (i != 0 && bsize != last_bsize) { + log_msg(LOG_DEFAULT, LVL_ERROR, "block sizes differ"); + rc = EINVAL; + goto error; + } + last_bsize = bsize; + } + + bd_srvs_init(&new_volume->hr_bds); + new_volume->hr_bds.ops = &hr_raid0_bd_ops; + new_volume->hr_bds.sarg = new_volume; + new_volume->nblocks = total_blocks; + new_volume->bsize = bsize; + + rc = hr_register_volume(new_volume); + if (rc != EOK) + goto error; + + return EOK; +error: + hr_fini_devs(new_volume); + return rc; +} + +/** @} + */ From 680e8c87feb0239e956482146d9d455038b8c571 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Thu, 5 Sep 2024 21:55:41 +0200 Subject: [PATCH 008/324] hr: initialize big_lock once --- uspace/srv/bd/hr/hr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index e2bce0198e..ad7d3fee5b 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -89,8 +89,6 @@ static void hr_create_srv(ipc_call_t *icall) hr_config->dev_no = size / sizeof(service_id_t); - fibril_mutex_initialize(&big_lock); - hr_volume_t *new_volume = calloc(1, sizeof(hr_volume_t)); if (new_volume == NULL) { rc = ENOMEM; @@ -205,6 +203,8 @@ int main(int argc, char **argv) return 1; } + fibril_mutex_initialize(&big_lock); + fibril_mutex_initialize(&hr_volumes_lock); list_initialize(&hr_volumes); From 68e357eabc38844f16a69c9fd002cdfc4f785db0 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Thu, 5 Sep 2024 22:54:51 +0200 Subject: [PATCH 009/324] hr: use array for devname and devices for now --- uspace/app/hrctl/hrctl.c | 95 +++++++++++++++++----------------- uspace/lib/device/include/hr.h | 7 ++- uspace/lib/device/src/hr.c | 16 ++---- uspace/srv/bd/hr/hr.c | 52 +++++++++++-------- uspace/srv/bd/hr/var.h | 4 +- 5 files changed, 86 insertions(+), 88 deletions(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index 9d48e0c445..0a6e3e31d6 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -81,46 +81,38 @@ static void usage(void) printf("%s", usage_str); } -static errno_t get_dev_svc_ids(int argc, char **argv, int optind, int dev_no, - service_id_t **rdevs) +static errno_t fill_config_devs(int argc, char **argv, int optind, + hr_config_t *cfg) { errno_t rc; - int i; - size_t k; - service_id_t *devs; + size_t i; - devs = calloc(dev_no, sizeof(service_id_t)); - if (devs == NULL) - return ENOMEM; - - for (i = optind, k = 0; i < argc; i++, k++) { - rc = loc_service_get_id(argv[i], &devs[k], 0); + for (i = 0; i < cfg->dev_no; i++) { + rc = loc_service_get_id(argv[optind++], &cfg->devs[i], 0); if (rc != EOK) { printf("hrctl: error resolving device \"%s\"\n", argv[i]); - free(devs); return EINVAL; } } - *rdevs = devs; - return EOK; } int main(int argc, char **argv) { errno_t rc; - int retval, c, dev_no; + int retval, c; bool create, assemble; - char *name = NULL; - service_id_t *devs = NULL; hr_t *hr; - hr_config_t hr_config; - hr_level_t level; + hr_config_t *cfg; + + cfg = calloc(1, sizeof(hr_config_t)); + if (cfg == NULL) + return 1; retval = 0; - level = hr_l_empty; - dev_no = 0; + cfg->level = hr_l_empty; + cfg->dev_no = 0; create = assemble = false; if (argc < 2) { @@ -142,46 +134,58 @@ int main(int argc, char **argv) printf("hrctl: status not implemented yet\n"); return 0; case 'a': - name = optarg; + if (str_size(optarg) > 31) { + printf("hrctl: device name longer than 31 bytes\n"); + return 1; + } + str_cpy(cfg->devname, 32, optarg); assemble = true; break; case 'c': - name = optarg; + if (str_size(optarg) > 31) { + printf("hrctl: device name longer than 31 bytes\n"); + return 1; + } + str_cpy(cfg->devname, 32, optarg); create = true; break; case 'l': - if (level != hr_l_empty) + if (cfg->level != hr_l_empty) goto bad; if (str_cmp(optarg, "linear") == 0) - level = hr_l_linear; + cfg->level = hr_l_linear; else - level = strtol(optarg, NULL, 10); + cfg->level = strtol(optarg, NULL, 10); break; case '0': - if (level != hr_l_empty) + if (cfg->level != hr_l_empty) goto bad; - level = hr_l_0; + cfg->level = hr_l_0; break; case '1': - if (level != hr_l_empty) + if (cfg->level != hr_l_empty) goto bad; - level = hr_l_1; + cfg->level = hr_l_1; break; case '5': - if (level != hr_l_empty) + if (cfg->level != hr_l_empty) goto bad; - level = hr_l_5; + cfg->level = hr_l_5; break; case 'L': - if (level != hr_l_empty) + if (cfg->level != hr_l_empty) goto bad; - level = hr_l_linear; + cfg->level = hr_l_linear; break; case 'n': - dev_no = strtol(optarg, NULL, 10); - if (dev_no + optind != argc) + cfg->dev_no = strtol(optarg, NULL, 10); + if ((int) cfg->dev_no + optind != argc) goto bad; - rc = get_dev_svc_ids(argc, argv, optind, dev_no, &devs); + if (cfg->dev_no > HR_MAXDEVS) { + printf("hrctl: too many devices\n"); + return 1; + } + rc = fill_config_devs(argc, argv, optind, cfg); if (rc != EOK) return 1; break; @@ -190,18 +194,12 @@ int main(int argc, char **argv) if ((create && assemble) || (!create && !assemble) || - (create && level == hr_l_empty) || - (assemble && level != hr_l_empty) || - (dev_no == 0)) { - free(devs); + (create && cfg->level == hr_l_empty) || + (assemble && cfg->level != hr_l_empty) || + (cfg->dev_no == 0)) { goto bad; } - hr_config.level = level; - hr_config.dev_no = dev_no; - hr_config.name = name; - hr_config.devs = devs; - rc = hr_sess_init(&hr); if (rc != EOK) { printf("hrctl: hr_sess_init() rc: %s\n", str_error(rc)); @@ -210,17 +208,18 @@ int main(int argc, char **argv) } if (create) { - rc = hr_create(hr, &hr_config); + rc = hr_create(hr, cfg); printf("hrctl: hr_create() rc: %s\n", str_error(rc)); } else if (assemble) { printf("hrctl: assemble not implemented yet\n"); } end: - free(devs); + free(cfg); hr_sess_destroy(hr); return retval; bad: + free(cfg); printf("hrctl: bad usage, try hrctl --help\n"); return 1; } diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index 4b558dfb3e..1aed7d8ea8 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -40,6 +40,9 @@ #include #include +/* for now */ +#define HR_MAXDEVS 4 + typedef struct hr { async_sess_t *sess; } hr_t; @@ -53,8 +56,8 @@ typedef enum hr_level { } hr_level_t; typedef struct hr_config { - char *name; - service_id_t *devs; + char devname[32]; + service_id_t devs[HR_MAXDEVS]; size_t dev_no; hr_level_t level; } hr_config_t; diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index 6f9b90be78..64dfaf1871 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -93,22 +93,12 @@ errno_t hr_create(hr_t *hr, hr_config_t *hr_config) aid_t req; exch = async_exchange_begin(hr->sess); - if (exch == NULL) { + if (exch == NULL) return EINVAL; - } - - req = async_send_1(exch, HR_CREATE, hr_config->level, NULL); - rc = async_data_write_start(exch, hr_config->name, - str_size(hr_config->name)); - if (rc != EOK) { - async_exchange_end(exch); - async_forget(req); - return rc; - } + req = async_send_0(exch, HR_CREATE, NULL); - rc = async_data_write_start(exch, hr_config->devs, - sizeof(service_id_t) * hr_config->dev_no); + rc = async_data_write_start(exch, hr_config, sizeof(hr_config_t)); if (rc != EOK) { async_exchange_end(exch); async_forget(req); diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index ad7d3fee5b..6170b93052 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include "var.h" @@ -63,43 +64,47 @@ static void hr_create_srv(ipc_call_t *icall) errno_t rc; size_t size; - hr_config_t *hr_config; + hr_config_t *cfg; + hr_volume_t *new_volume; + ipc_call_t call; - hr_config = calloc(1, sizeof(hr_config_t)); - if (hr_config == NULL) { - async_answer_0(icall, ENOMEM); + if (!async_data_write_receive(&call, &size)) { + async_answer_0(&call, EREFUSED); + async_answer_0(icall, EREFUSED); return; } - hr_config->level = ipc_get_arg1(icall); - - rc = async_data_write_accept((void **) &hr_config->name, true, 0, 0, 0, - NULL); - if (rc != EOK) { - async_answer_0(icall, EREFUSED); + if (size != sizeof(hr_config_t)) { + async_answer_0(&call, EINVAL); + async_answer_0(icall, EINVAL); return; } - rc = async_data_write_accept((void **) &hr_config->devs, false, - sizeof(service_id_t), 0, 0, &size); - if (rc != EOK) { - async_answer_0(icall, EREFUSED); + cfg = calloc(1, sizeof(hr_config_t)); + if (cfg == NULL) { + async_answer_0(&call, ENOMEM); + async_answer_0(icall, ENOMEM); return; } - hr_config->dev_no = size / sizeof(service_id_t); + rc = async_data_write_finalize(&call, cfg, size); + if (rc != EOK) { + async_answer_0(&call, rc); + async_answer_0(icall, rc); + } - hr_volume_t *new_volume = calloc(1, sizeof(hr_volume_t)); + new_volume = calloc(1, sizeof(hr_volume_t)); if (new_volume == NULL) { rc = ENOMEM; goto end; } - new_volume->devname = hr_config->name; - new_volume->level = hr_config->level; - new_volume->dev_no = hr_config->dev_no; - new_volume->devs = hr_config->devs; - switch (hr_config->level) { + str_cpy(new_volume->devname, 32, cfg->devname); + memcpy(new_volume->devs, cfg->devs, sizeof(service_id_t) * HR_MAXDEVS); + new_volume->level = cfg->level; + new_volume->dev_no = cfg->dev_no; + + switch (new_volume->level) { case hr_l_1: new_volume->hr_ops.create = hr_raid1_create; break; @@ -114,8 +119,9 @@ static void hr_create_srv(ipc_call_t *icall) } rc = new_volume->hr_ops.create(new_volume); - if (rc != EOK) + if (rc != EOK) { goto end; + } fibril_mutex_lock(&hr_volumes_lock); list_append(&new_volume->lvolumes, &hr_volumes); @@ -125,7 +131,7 @@ static void hr_create_srv(ipc_call_t *icall) new_volume->devname, new_volume->svc_id); end: - free(hr_config); + free(cfg); async_answer_0(icall, rc); } diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index 246895df8c..befa9c9945 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -52,8 +52,8 @@ typedef struct hr_volume { hr_ops_t hr_ops; bd_srvs_t hr_bds; link_t lvolumes; - char *devname; - service_id_t *devs; + char devname[32]; + service_id_t devs[HR_MAXDEVS]; uint64_t nblocks; size_t bsize; service_id_t svc_id; From 44ea48e091b7d0b014e67f84aec7084848680332 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Thu, 5 Sep 2024 22:56:28 +0200 Subject: [PATCH 010/324] hr: register hr array under "devices/XXXX" --- uspace/srv/bd/hr/util.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 72f34bf119..ea8aaf9ce0 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -38,6 +38,8 @@ #include #include #include +#include +#include #include #include "var.h" @@ -82,8 +84,12 @@ errno_t hr_register_volume(hr_volume_t *new_volume) errno_t rc; service_id_t new_id; category_id_t cat_id; + char *fullname = NULL; - rc = loc_service_register(hr_srv, new_volume->devname, &new_id); + if (asprintf(&fullname, "devices/%s", new_volume->devname) < 0) + return ENOMEM; + + rc = loc_service_register(hr_srv, fullname, &new_id); if (rc != EOK) { log_msg(LOG_DEFAULT, LVL_ERROR, "unable to register device \"%s\": %s\n", @@ -109,6 +115,7 @@ errno_t hr_register_volume(hr_volume_t *new_volume) new_volume->svc_id = new_id; error: + free(fullname); return rc; } From e19233962560a4f7d4b8f8848b45c7a034b09ee9 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Thu, 5 Sep 2024 23:58:12 +0200 Subject: [PATCH 011/324] hrctl: add option for creating array from config file --- uspace/app/hrctl/hrctl.c | 135 +++++++++++++++++++++++--- uspace/app/hrctl/meson.build | 4 +- uspace/app/hrctl/sample_hr_config.sif | 9 ++ 3 files changed, 134 insertions(+), 14 deletions(-) create mode 100644 uspace/app/hrctl/sample_hr_config.sif diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index 0a6e3e31d6..8cd9b8a6a8 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -36,28 +36,35 @@ #include #include #include +#include #include #include #include #include +#define HRCTL_SAMPLE_CONFIG_PATH "/cfg/sample_hr_config.sif" + static void usage(void); +static errno_t fill_config_devs(int, char **, int, hr_config_t *); +static errno_t load_config(const char *, hr_config_t *); static const char usage_str[] = "Usage: hrctl [OPTION]... -n ...\n" "\n" "Options:\n" - " -h, --help display this help and exit\n" - " -s, --status display status of active arrays\n" - " -a, --assemble=NAME assemble an existing array\n" - " -c, --create=NAME create new array\n" - " -n non-zero number of devices\n" - " -l, --level=LEVEL set the RAID level,\n" - " valid values: 0, 1, 5, linear\n" - " -0 striping\n" - " -1 mirroring\n" - " -5 distributed parity\n" - " -L linear concatenation\n" + " -h, --help display this help and exit\n" + " -C, --config-file=path create an array from file,\n" + " sample file at: " HRCTL_SAMPLE_CONFIG_PATH "\n" + " -s, --status display status of active arrays\n" + " -a, --assemble=NAME assemble an existing array\n" + " -c, --create=NAME create new array\n" + " -n non-zero number of devices\n" + " -l, --level=LEVEL set the RAID level,\n" + " valid values: 0, 1, 5, linear\n" + " -0 striping\n" + " -1 mirroring\n" + " -5 distributed parity\n" + " -L linear concatenation\n" "\n" "Example usage:\n" " hrctl --create /hr0 -0 -n 2 devices/\\hw\\0 devices/\\hw\\1\n" @@ -73,6 +80,7 @@ static struct option const long_options[] = { { "assemble", required_argument, 0, 'a' }, { "create", required_argument, 0, 'c' }, { "level", required_argument, 0, 'l' }, + { "config-file", required_argument, 0, 'C' }, { 0, 0, 0, 0 } }; @@ -98,6 +106,97 @@ static errno_t fill_config_devs(int argc, char **argv, int optind, return EOK; } +static errno_t load_config(const char *path, hr_config_t *cfg) +{ + errno_t rc; + size_t i; + sif_doc_t *doc = NULL; + sif_node_t *narrays; + sif_node_t *rnode; + sif_node_t *narray; + sif_node_t *nextent; + const char *ntype; + const char *devname; + const char *level_str; + const char *dev_no_str; + const char *extent_devname; + + rc = sif_load(path, &doc); + if (rc != EOK) + goto error; + + rnode = sif_get_root(doc); + + narrays = sif_node_first_child(rnode); + ntype = sif_node_get_type(narrays); + if (str_cmp(ntype, "arrays") != 0) { + rc = EIO; + goto error; + } + + narray = sif_node_first_child(narrays); + ntype = sif_node_get_type(narray); + if (str_cmp(ntype, "array") != 0) { + rc = EIO; + goto error; + } + + devname = sif_node_get_attr(narray, "devname"); + if (devname == NULL) { + rc = EIO; + goto error; + } + str_cpy(cfg->devname, 32, devname); + + level_str = sif_node_get_attr(narray, "level"); + if (level_str == NULL) { + rc = EIO; + goto error; + } + cfg->level = strtol(level_str, NULL, 10); + + dev_no_str = sif_node_get_attr(narray, "n"); + if (dev_no_str == NULL) { + rc = EIO; + goto error; + } + cfg->dev_no = strtol(dev_no_str, NULL, 10); + + nextent = sif_node_first_child(narray); + for (i = 0; i < cfg->dev_no; i++) { + if (nextent == NULL) { + rc = EINVAL; + goto error; + } + + ntype = sif_node_get_type(nextent); + if (str_cmp(ntype, "extent") != 0) { + rc = EIO; + goto error; + } + + extent_devname = sif_node_get_attr(nextent, "devname"); + if (extent_devname == NULL) { + rc = EIO; + goto error; + } + + rc = loc_service_get_id(extent_devname, &cfg->devs[i], 0); + if (rc != EOK) { + printf("hrctl: error resolving device \"%s\"\n", + extent_devname); + return EINVAL; + } + + nextent = sif_node_next_child(nextent); + } + +error: + if (doc != NULL) + sif_delete(doc); + return rc; +} + int main(int argc, char **argv) { errno_t rc; @@ -124,7 +223,7 @@ int main(int argc, char **argv) optind = 0; while (c != -1) { - c = getopt_long(argc, argv, "hsc:a:l:015Ln:", + c = getopt_long(argc, argv, "hsC:c:a:l:015Ln:", long_options, NULL); switch (c) { case 'h': @@ -132,7 +231,7 @@ int main(int argc, char **argv) return 0; case 's': printf("hrctl: status not implemented yet\n"); - return 0; + return 1; case 'a': if (str_size(optarg) > 31) { printf("hrctl: device name longer than 31 bytes\n"); @@ -141,6 +240,15 @@ int main(int argc, char **argv) str_cpy(cfg->devname, 32, optarg); assemble = true; break; + case 'C': + /* only support 1 array inside config for now XXX */ + rc = load_config(optarg, cfg); + if (rc != EOK) { + printf("hrctl: failed to load config\n"); + return 1; + } + create = true; + goto skip; case 'c': if (str_size(optarg) > 31) { printf("hrctl: device name longer than 31 bytes\n"); @@ -192,6 +300,7 @@ int main(int argc, char **argv) } } +skip: if ((create && assemble) || (!create && !assemble) || (create && cfg->level == hr_l_empty) || diff --git a/uspace/app/hrctl/meson.build b/uspace/app/hrctl/meson.build index 84d2fa1eb0..1987e908b5 100644 --- a/uspace/app/hrctl/meson.build +++ b/uspace/app/hrctl/meson.build @@ -26,5 +26,7 @@ # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # -deps = [ 'device' ] +deps = [ 'device', 'sif' ] src = files('hrctl.c') + +installed_data += { 'name': 'sample_hr_config.sif', 'dir': '/cfg' } diff --git a/uspace/app/hrctl/sample_hr_config.sif b/uspace/app/hrctl/sample_hr_config.sif new file mode 100644 index 0000000000..7a48c4bcc8 --- /dev/null +++ b/uspace/app/hrctl/sample_hr_config.sif @@ -0,0 +1,9 @@ + + + + + + + + + From 095a9899dd171eafbfd3db014e011dc0b000c057 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 6 Sep 2024 00:31:28 +0200 Subject: [PATCH 012/324] hr: add status printing --- uspace/app/hrctl/hrctl.c | 6 +- uspace/lib/device/include/hr.h | 10 ++++ uspace/lib/device/include/ipc/hr.h | 3 +- uspace/lib/device/src/hr.c | 91 ++++++++++++++++++++++++++++++ uspace/srv/bd/hr/hr.c | 64 +++++++++++++++++++++ 5 files changed, 171 insertions(+), 3 deletions(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index 8cd9b8a6a8..90466a6030 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -230,8 +230,10 @@ int main(int argc, char **argv) usage(); return 0; case 's': - printf("hrctl: status not implemented yet\n"); - return 1; + rc = hr_print_status(); + if (rc != EOK) + return 1; + return 0; case 'a': if (str_size(optarg) > 31) { printf("hrctl: device name longer than 31 bytes\n"); diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index 1aed7d8ea8..f690247bd2 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -62,10 +62,20 @@ typedef struct hr_config { hr_level_t level; } hr_config_t; +typedef struct hr_vol_info { + service_id_t extents[HR_MAXDEVS]; + size_t extent_no; + service_id_t svc_id; + hr_level_t level; + uint64_t nblocks; + size_t bsize; +} hr_vol_info_t; + extern errno_t hr_sess_init(hr_t **); extern void hr_sess_destroy(hr_t *); extern errno_t hr_create(hr_t *, hr_config_t *); +extern errno_t hr_print_status(void); #endif diff --git a/uspace/lib/device/include/ipc/hr.h b/uspace/lib/device/include/ipc/hr.h index 3effc98452..25b15c23d9 100644 --- a/uspace/lib/device/include/ipc/hr.h +++ b/uspace/lib/device/include/ipc/hr.h @@ -38,7 +38,8 @@ #include typedef enum { - HR_CREATE = IPC_FIRST_USER_METHOD + HR_CREATE = IPC_FIRST_USER_METHOD, + HR_STATUS } hr_request_t; #endif diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index 64dfaf1871..096716b05e 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -113,5 +113,96 @@ errno_t hr_create(hr_t *hr, hr_config_t *hr_config) return EOK; } +static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info) +{ + errno_t rc; + size_t i; + char *devname; + + printf("--- vol %zu ---\n", index); + + printf("svc_id: %lu\n", vol_info->svc_id); + + rc = loc_service_get_name(vol_info->svc_id, &devname); + if (rc != EOK) + return rc; + printf("devname: %s\n", devname); + + printf("level: %d\n", vol_info->level); + printf("nblocks: %lu\n", vol_info->nblocks); + printf("bsize: %zu\n", vol_info->bsize); + + printf("extents: [index] [devname]\n"); + for (i = 0; i < vol_info->extent_no; i++) { + rc = loc_service_get_name(vol_info->extents[i], &devname); + if (rc != EOK) + return rc; + printf(" %zu %s\n", i, devname); + } + return EOK; +} + +errno_t hr_print_status(void) +{ + hr_t *hr; + errno_t rc, retval; + async_exch_t *exch; + aid_t req; + size_t size, i; + hr_vol_info_t *vols; + + rc = hr_sess_init(&hr); + if (rc != EOK) + return rc; + + exch = async_exchange_begin(hr->sess); + if (exch == NULL) + return EINVAL; + + req = async_send_0(exch, HR_STATUS, NULL); + + rc = async_data_read_start(exch, &size, sizeof(size_t)); + if (rc != EOK) { + async_exchange_end(exch); + async_forget(req); + return rc; + } + + vols = calloc(size, sizeof(hr_vol_info_t)); + if (vols == NULL) { + async_exchange_end(exch); + async_forget(req); + return ENOMEM; + } + + for (i = 0; i < size; i++) { + rc = async_data_read_start(exch, &vols[i], + sizeof(hr_vol_info_t)); + if (rc != EOK) { + async_exchange_end(exch); + async_forget(req); + goto error; + } + } + + async_exchange_end(exch); + async_wait_for(req, &retval); + if (retval != EOK) { + rc = retval; + goto error; + } + + for (i = 0; i < size; i++) { + rc = print_vol_info(i, &vols[i]); + if (rc != EOK) + goto error; + } + +error: + if (vols != NULL) + free(vols); + return rc; +} + /** @} */ diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 6170b93052..d637639285 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -135,6 +135,67 @@ static void hr_create_srv(ipc_call_t *icall) async_answer_0(icall, rc); } +static void hr_print_status_srv(ipc_call_t *icall) +{ + log_msg(LOG_DEFAULT, LVL_NOTE, "hr_status_srv()"); + + errno_t rc; + size_t vol_cnt = 0; + hr_vol_info_t info; + ipc_call_t call; + size_t size; + + fibril_mutex_lock(&hr_volumes_lock); + + vol_cnt = list_count(&hr_volumes); + + if (!async_data_read_receive(&call, &size)) { + rc = EREFUSED; + goto error; + } + + if (size != sizeof(size_t)) { + rc = EINVAL; + goto error; + } + + rc = async_data_read_finalize(&call, &vol_cnt, size); + if (rc != EOK) + goto error; + + list_foreach(hr_volumes, lvolumes, hr_volume_t, volume) { + memcpy(info.extents, volume->devs, + sizeof(service_id_t) * HR_MAXDEVS); + info.svc_id = volume->svc_id; + info.extent_no = volume->dev_no; + info.level = volume->level; + info.nblocks = volume->nblocks; + info.bsize = volume->bsize; + + if (!async_data_read_receive(&call, &size)) { + rc = EREFUSED; + goto error; + } + + if (size != sizeof(hr_vol_info_t)) { + rc = EINVAL; + goto error; + } + + rc = async_data_read_finalize(&call, &info, size); + if (rc != EOK) + goto error; + } + + fibril_mutex_unlock(&hr_volumes_lock); + async_answer_0(icall, EOK); + return; +error: + fibril_mutex_unlock(&hr_volumes_lock); + async_answer_0(&call, rc); + async_answer_0(icall, rc); +} + static void hr_ctl_conn(ipc_call_t *icall, void *arg) { log_msg(LOG_DEFAULT, LVL_NOTE, "hr_ctl_conn()"); @@ -155,6 +216,9 @@ static void hr_ctl_conn(ipc_call_t *icall, void *arg) case HR_CREATE: hr_create_srv(&call); break; + case HR_STATUS: + hr_print_status_srv(&call); + break; default: async_answer_0(&call, EINVAL); } From ee83e9cf5b7876922b8efc19ac46344d1f5194bf Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 6 Sep 2024 00:44:57 +0200 Subject: [PATCH 013/324] hrctl: use sizeof(devname) instead of a constant --- uspace/app/hrctl/hrctl.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index 90466a6030..c54f41dfd0 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -67,12 +67,14 @@ static const char usage_str[] = " -L linear concatenation\n" "\n" "Example usage:\n" - " hrctl --create /hr0 -0 -n 2 devices/\\hw\\0 devices/\\hw\\1\n" + " hrctl --create hr0 -0 -n 2 devices/\\hw\\0 devices/\\hw\\1\n" " - creates new mirroring RAID device named /hr0 consisting\n" " of 2 drives\n" - " hrctl --assemble /hr0 -n 2 devices/\\hw\\0 devices/\\hw\\1\n" + " hrctl --assemble hr0 -n 2 devices/\\hw\\0 devices/\\hw\\1\n" " - assembles RAID device named /hr0 consisting of 2 drives,\n" - " that were previously in an array\n"; + " that were previously in an array\n" + "Limitations:\n" + " - device name must be less than 32 characters in size\n"; static struct option const long_options[] = { { "help", no_argument, 0, 'h' }, @@ -96,11 +98,13 @@ static errno_t fill_config_devs(int argc, char **argv, int optind, size_t i; for (i = 0; i < cfg->dev_no; i++) { - rc = loc_service_get_id(argv[optind++], &cfg->devs[i], 0); + rc = loc_service_get_id(argv[optind], &cfg->devs[i], 0); if (rc != EOK) { - printf("hrctl: error resolving device \"%s\"\n", argv[i]); + printf("hrctl: error resolving device \"%s\"\n", argv[optind]); return EINVAL; } + + optind++; } return EOK; @@ -146,7 +150,7 @@ static errno_t load_config(const char *path, hr_config_t *cfg) rc = EIO; goto error; } - str_cpy(cfg->devname, 32, devname); + str_cpy(cfg->devname, sizeof(cfg->devname), devname); level_str = sif_node_get_attr(narray, "level"); if (level_str == NULL) { @@ -235,11 +239,11 @@ int main(int argc, char **argv) return 1; return 0; case 'a': - if (str_size(optarg) > 31) { - printf("hrctl: device name longer than 31 bytes\n"); + if (str_size(optarg) > sizeof(cfg->devname) - 1) { + printf("hrctl: device name too long\n"); return 1; } - str_cpy(cfg->devname, 32, optarg); + str_cpy(cfg->devname, sizeof(cfg->devname), optarg); assemble = true; break; case 'C': @@ -252,11 +256,11 @@ int main(int argc, char **argv) create = true; goto skip; case 'c': - if (str_size(optarg) > 31) { - printf("hrctl: device name longer than 31 bytes\n"); + if (str_size(optarg) > sizeof(cfg->devname) - 1) { + printf("hrctl: device name too long\n"); return 1; } - str_cpy(cfg->devname, 32, optarg); + str_cpy(cfg->devname, sizeof(cfg->devname), optarg); create = true; break; case 'l': From b0f13664307c5f49642065cfc42aec7d4a3040cb Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 6 Sep 2024 13:37:54 +0200 Subject: [PATCH 014/324] hr: write persistent metadata, assemble array from metadata --- uspace/app/hrctl/hrctl.c | 92 +++++++++------ uspace/lib/device/include/hr.h | 1 + uspace/lib/device/include/ipc/hr.h | 1 + uspace/lib/device/src/hr.c | 27 +++++ uspace/srv/bd/hr/hr.c | 147 +++++++++++++++++++++-- uspace/srv/bd/hr/meson.build | 2 +- uspace/srv/bd/hr/raid0.c | 61 +++------- uspace/srv/bd/hr/raid1.c | 70 ++++------- uspace/srv/bd/hr/superblock.c | 182 +++++++++++++++++++++++++++++ uspace/srv/bd/hr/superblock.h | 64 ++++++++++ uspace/srv/bd/hr/util.c | 63 +++++++++- uspace/srv/bd/hr/util.h | 2 + uspace/srv/bd/hr/var.h | 6 +- 13 files changed, 578 insertions(+), 140 deletions(-) create mode 100644 uspace/srv/bd/hr/superblock.c create mode 100644 uspace/srv/bd/hr/superblock.h diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index c54f41dfd0..ab8436a83b 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -52,19 +52,20 @@ static const char usage_str[] = "Usage: hrctl [OPTION]... -n ...\n" "\n" "Options:\n" - " -h, --help display this help and exit\n" - " -C, --config-file=path create an array from file,\n" - " sample file at: " HRCTL_SAMPLE_CONFIG_PATH "\n" - " -s, --status display status of active arrays\n" - " -a, --assemble=NAME assemble an existing array\n" - " -c, --create=NAME create new array\n" - " -n non-zero number of devices\n" - " -l, --level=LEVEL set the RAID level,\n" - " valid values: 0, 1, 5, linear\n" - " -0 striping\n" - " -1 mirroring\n" - " -5 distributed parity\n" - " -L linear concatenation\n" + " -h, --help display this help and exit\n" + " -C, --create-file=path create an array from file,\n" + " sample file at: " HRCTL_SAMPLE_CONFIG_PATH "\n" + " -A, --assemble-file=path create an array from file\n" + " -s, --status display status of active arrays\n" + " -c, --create=NAME create new array\n" + " -a, --assemble=NAME assemble an existing array\n" + " -n non-zero number of devices\n" + " -l, --level=LEVEL set the RAID level,\n" + " valid values: 0, 1, 5, linear\n" + " -0 striping\n" + " -1 mirroring\n" + " -5 distributed parity\n" + " -L linear concatenation\n" "\n" "Example usage:\n" " hrctl --create hr0 -0 -n 2 devices/\\hw\\0 devices/\\hw\\1\n" @@ -82,7 +83,8 @@ static struct option const long_options[] = { { "assemble", required_argument, 0, 'a' }, { "create", required_argument, 0, 'c' }, { "level", required_argument, 0, 'l' }, - { "config-file", required_argument, 0, 'C' }, + { "create-file", required_argument, 0, 'C' }, + { "assemble-file", required_argument, 0, 'A' }, { 0, 0, 0, 0 } }; @@ -153,11 +155,12 @@ static errno_t load_config(const char *path, hr_config_t *cfg) str_cpy(cfg->devname, sizeof(cfg->devname), devname); level_str = sif_node_get_attr(narray, "level"); - if (level_str == NULL) { - rc = EIO; - goto error; - } - cfg->level = strtol(level_str, NULL, 10); + if (level_str == NULL) + cfg->level = hr_l_empty; + else if (str_cmp(level_str, "linear") == 0) + cfg->level = hr_l_linear; + else + cfg->level = strtol(level_str, NULL, 10); dev_no_str = sif_node_get_attr(narray, "n"); if (dev_no_str == NULL) { @@ -227,7 +230,7 @@ int main(int argc, char **argv) optind = 0; while (c != -1) { - c = getopt_long(argc, argv, "hsC:c:a:l:015Ln:", + c = getopt_long(argc, argv, "hsC:c:A:a:l:015Ln:", long_options, NULL); switch (c) { case 'h': @@ -238,30 +241,38 @@ int main(int argc, char **argv) if (rc != EOK) return 1; return 0; - case 'a': + case 'C': + /* only support 1 array inside config for now XXX */ + rc = load_config(optarg, cfg); + if (rc != EOK) { + printf("hrctl: failed to load config\n"); + return 1; + } + create = true; + goto skip; + case 'c': if (str_size(optarg) > sizeof(cfg->devname) - 1) { printf("hrctl: device name too long\n"); return 1; } str_cpy(cfg->devname, sizeof(cfg->devname), optarg); - assemble = true; + create = true; break; - case 'C': - /* only support 1 array inside config for now XXX */ + case 'A': rc = load_config(optarg, cfg); if (rc != EOK) { printf("hrctl: failed to load config\n"); return 1; } - create = true; + assemble = true; goto skip; - case 'c': + case 'a': if (str_size(optarg) > sizeof(cfg->devname) - 1) { printf("hrctl: device name too long\n"); return 1; } str_cpy(cfg->devname, sizeof(cfg->devname), optarg); - create = true; + assemble = true; break; case 'l': if (cfg->level != hr_l_empty) @@ -295,10 +306,6 @@ int main(int argc, char **argv) cfg->dev_no = strtol(optarg, NULL, 10); if ((int) cfg->dev_no + optind != argc) goto bad; - if (cfg->dev_no > HR_MAXDEVS) { - printf("hrctl: too many devices\n"); - return 1; - } rc = fill_config_devs(argc, argv, optind, cfg); if (rc != EOK) return 1; @@ -307,12 +314,22 @@ int main(int argc, char **argv) } skip: - if ((create && assemble) || - (!create && !assemble) || - (create && cfg->level == hr_l_empty) || - (assemble && cfg->level != hr_l_empty) || - (cfg->dev_no == 0)) { + if ((create && assemble) || (!create && !assemble)) goto bad; + + if (create && cfg->level == hr_l_empty) { + printf("hrctl: invalid level, exiting\n"); + return 1; + } + + if (cfg->dev_no > HR_MAXDEVS) { + printf("hrctl: too many devices, exiting\n"); + return 1; + } + + if (cfg->dev_no == 0) { + printf("hrctl: invalid number of devices, exiting\n"); + return 1; } rc = hr_sess_init(&hr); @@ -326,7 +343,8 @@ int main(int argc, char **argv) rc = hr_create(hr, cfg); printf("hrctl: hr_create() rc: %s\n", str_error(rc)); } else if (assemble) { - printf("hrctl: assemble not implemented yet\n"); + rc = hr_assemble(hr, cfg); + printf("hrctl: hr_assemble() rc: %s\n", str_error(rc)); } end: diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index f690247bd2..cfa48a9501 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -75,6 +75,7 @@ extern errno_t hr_sess_init(hr_t **); extern void hr_sess_destroy(hr_t *); extern errno_t hr_create(hr_t *, hr_config_t *); +extern errno_t hr_assemble(hr_t *, hr_config_t *); extern errno_t hr_print_status(void); #endif diff --git a/uspace/lib/device/include/ipc/hr.h b/uspace/lib/device/include/ipc/hr.h index 25b15c23d9..cd535bf40d 100644 --- a/uspace/lib/device/include/ipc/hr.h +++ b/uspace/lib/device/include/ipc/hr.h @@ -39,6 +39,7 @@ typedef enum { HR_CREATE = IPC_FIRST_USER_METHOD, + HR_ASSEMBLE, HR_STATUS } hr_request_t; diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index 096716b05e..f3be2578a8 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -113,6 +113,33 @@ errno_t hr_create(hr_t *hr, hr_config_t *hr_config) return EOK; } +errno_t hr_assemble(hr_t *hr, hr_config_t *hr_config) +{ + errno_t rc, retval; + async_exch_t *exch; + aid_t req; + + exch = async_exchange_begin(hr->sess); + if (exch == NULL) + return EINVAL; + + req = async_send_0(exch, HR_ASSEMBLE, NULL); + + rc = async_data_write_start(exch, hr_config, sizeof(hr_config_t)); + if (rc != EOK) { + async_exchange_end(exch); + async_forget(req); + return rc; + } + + async_exchange_end(exch); + async_wait_for(req, &retval); + if (retval != EOK) + return retval; + + return EOK; +} + static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info) { errno_t rc; diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index d637639285..3d0635a2e9 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -48,6 +48,8 @@ #include #include +#include "superblock.h" +#include "util.h" #include "var.h" loc_srv_t *hr_srv; @@ -58,6 +60,7 @@ static list_t hr_volumes; static service_id_t ctl_sid; + static void hr_create_srv(ipc_call_t *icall) { log_msg(LOG_DEFAULT, LVL_NOTE, "hr_create_srv()"); @@ -91,12 +94,14 @@ static void hr_create_srv(ipc_call_t *icall) if (rc != EOK) { async_answer_0(&call, rc); async_answer_0(icall, rc); + return; } new_volume = calloc(1, sizeof(hr_volume_t)); if (new_volume == NULL) { - rc = ENOMEM; - goto end; + free(cfg); + async_answer_0(icall, ENOMEM); + return; } str_cpy(new_volume->devname, 32, cfg->devname); @@ -104,6 +109,21 @@ static void hr_create_srv(ipc_call_t *icall) new_volume->level = cfg->level; new_volume->dev_no = cfg->dev_no; + rc = hr_init_devs(new_volume); + if (rc != EOK) { + free(cfg); + async_answer_0(icall, rc); + return; + } + + rc = hr_check_devs(new_volume); + if (rc != EOK) + goto error; + + rc = hr_write_meta_to_vol(new_volume); + if (rc != EOK) + goto error; + switch (new_volume->level) { case hr_l_1: new_volume->hr_ops.create = hr_raid1_create; @@ -112,27 +132,132 @@ static void hr_create_srv(ipc_call_t *icall) new_volume->hr_ops.create = hr_raid0_create; break; default: - log_msg(LOG_DEFAULT, LVL_NOTE, - "level %d not implemented yet\n", new_volume->level); + log_msg(LOG_DEFAULT, LVL_ERROR, + "level %d not implemented yet", new_volume->level); rc = EINVAL; - goto end; + goto error; } rc = new_volume->hr_ops.create(new_volume); + if (rc != EOK) + goto error; + + fibril_mutex_lock(&hr_volumes_lock); + list_append(&new_volume->lvolumes, &hr_volumes); + fibril_mutex_unlock(&hr_volumes_lock); + + log_msg(LOG_DEFAULT, LVL_NOTE, "created volume \"%s\" (%" PRIun ")", + new_volume->devname, new_volume->svc_id); + + free(cfg); + async_answer_0(icall, rc); + return; +error: + free(cfg); + hr_fini_devs(new_volume); + async_answer_0(icall, rc); +} + +static void hr_assemble_srv(ipc_call_t *icall) +{ + log_msg(LOG_DEFAULT, LVL_NOTE, "hr_assemble_srv()"); + + errno_t rc; + size_t size; + hr_config_t *cfg; + hr_volume_t *new_volume; + ipc_call_t call; + + if (!async_data_write_receive(&call, &size)) { + async_answer_0(&call, EREFUSED); + async_answer_0(icall, EREFUSED); + return; + } + + if (size != sizeof(hr_config_t)) { + async_answer_0(&call, EINVAL); + async_answer_0(icall, EINVAL); + return; + } + + cfg = calloc(1, sizeof(hr_config_t)); + if (cfg == NULL) { + async_answer_0(&call, ENOMEM); + async_answer_0(icall, ENOMEM); + return; + } + + rc = async_data_write_finalize(&call, cfg, size); + if (rc != EOK) { + async_answer_0(&call, rc); + async_answer_0(icall, rc); + return; + } + + new_volume = calloc(1, sizeof(hr_volume_t)); + if (new_volume == NULL) { + free(cfg); + async_answer_0(icall, ENOMEM); + return; + } + + str_cpy(new_volume->devname, 32, cfg->devname); + memcpy(new_volume->devs, cfg->devs, sizeof(service_id_t) * HR_MAXDEVS); + new_volume->dev_no = cfg->dev_no; + + if (cfg->level != hr_l_empty) + log_msg(LOG_DEFAULT, LVL_WARN, + "level manually set when assembling, ingoring"); + + new_volume->level = hr_l_empty; + + rc = hr_init_devs(new_volume); if (rc != EOK) { - goto end; + free(cfg); + async_answer_0(icall, rc); + return; } + rc = hr_check_devs(new_volume); + if (rc != EOK) + goto error; + + rc = hr_get_vol_from_meta(cfg, new_volume); + if (rc != EOK) + goto error; + + switch (new_volume->level) { + case hr_l_1: + new_volume->hr_ops.create = hr_raid1_create; + break; + case hr_l_0: + new_volume->hr_ops.create = hr_raid0_create; + break; + default: + log_msg(LOG_DEFAULT, LVL_ERROR, + "level %d not implemented yet", new_volume->level); + rc = EINVAL; + goto error; + } + + rc = new_volume->hr_ops.create(new_volume); + if (rc != EOK) + goto error; + fibril_mutex_lock(&hr_volumes_lock); list_append(&new_volume->lvolumes, &hr_volumes); fibril_mutex_unlock(&hr_volumes_lock); - log_msg(LOG_DEFAULT, LVL_NOTE, "created volume \"%s\" (%" PRIun ")\n", + log_msg(LOG_DEFAULT, LVL_NOTE, "assembled volume \"%s\" (%" PRIun ")", new_volume->devname, new_volume->svc_id); -end: free(cfg); async_answer_0(icall, rc); + return; +error: + free(cfg); + hr_fini_devs(new_volume); + async_answer_0(icall, rc); } static void hr_print_status_srv(ipc_call_t *icall) @@ -169,7 +294,8 @@ static void hr_print_status_srv(ipc_call_t *icall) info.svc_id = volume->svc_id; info.extent_no = volume->dev_no; info.level = volume->level; - info.nblocks = volume->nblocks; + /* print usable number of blocks */ + info.nblocks = volume->data_blkno; info.bsize = volume->bsize; if (!async_data_read_receive(&call, &size)) { @@ -219,6 +345,9 @@ static void hr_ctl_conn(ipc_call_t *icall, void *arg) case HR_STATUS: hr_print_status_srv(&call); break; + case HR_ASSEMBLE: + hr_assemble_srv(&call); + break; default: async_answer_0(&call, EINVAL); } diff --git a/uspace/srv/bd/hr/meson.build b/uspace/srv/bd/hr/meson.build index ee66fa6e03..29b673d98c 100644 --- a/uspace/srv/bd/hr/meson.build +++ b/uspace/srv/bd/hr/meson.build @@ -27,4 +27,4 @@ # deps = [ 'block', 'device' ] -src = files('hr.c', 'raid0.c', 'raid1.c', 'util.c') +src = files('hr.c', 'raid0.c', 'raid1.c', 'superblock.c', 'util.c') diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index 2f1075a2dc..3f0bcd5f46 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -47,8 +47,8 @@ #include #include -#include "var.h" #include "util.h" +#include "var.h" extern fibril_mutex_t big_lock; extern loc_srv_t *hr_srv; @@ -63,8 +63,6 @@ static errno_t hr_raid0_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, static errno_t hr_raid0_bd_get_block_size(bd_srv_t *, size_t *); static errno_t hr_raid0_bd_get_num_blocks(bd_srv_t *, aoff64_t *); -#define strip_size DATA_XFER_LIMIT - static bd_ops_t hr_raid0_bd_ops = { .open = hr_raid0_bd_open, .close = hr_raid0_bd_close, @@ -79,7 +77,7 @@ static void raid0_geometry(uint64_t x, hr_volume_t *vol, size_t *extent, uint64_t *phys_block) { uint64_t N = vol->dev_no; /* extents */ - uint64_t L = strip_size / vol->bsize; /* size of strip in blocks */ + uint64_t L = HR_STRIP_SIZE / vol->bsize; /* size of strip in blocks */ uint64_t i = (x / L) % N; /* extent */ uint64_t j = (x / L) / N; /* stripe */ @@ -113,6 +111,9 @@ static errno_t hr_raid0_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) size_t left = cnt; while (left != 0) { raid0_geometry(ba++, vol, &extent, &phys_block); + rc = hr_calc_ba(vol, cnt, &ba); + if (rc != EOK) + break; rc = block_sync_cache(vol->devs[extent], phys_block, 1); if (rc != EOK) break; @@ -139,6 +140,9 @@ static errno_t hr_raid0_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, size_t left = cnt; while (left != 0) { raid0_geometry(ba++, vol, &extent, &phys_block); + rc = hr_calc_ba(vol, cnt, &ba); + if (rc != EOK) + break; rc = block_read_direct(vol->devs[extent], phys_block, 1, buf); buf = buf + vol->bsize; if (rc != EOK) @@ -166,6 +170,9 @@ static errno_t hr_raid0_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, size_t left = cnt; while (left != 0) { raid0_geometry(ba++, vol, &extent, &phys_block); + rc = hr_calc_ba(vol, cnt, &phys_block); + if (rc != EOK) + break; rc = block_write_direct(vol->devs[extent], phys_block, 1, data); data = data + vol->bsize; if (rc != EOK) @@ -189,12 +196,14 @@ static errno_t hr_raid0_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb) { hr_volume_t *vol = bd->srvs->sarg; - *rnb = vol->nblocks; + *rnb = vol->data_blkno; return EOK; } errno_t hr_raid0_create(hr_volume_t *new_volume) { + errno_t rc; + assert(new_volume->level == hr_l_0); if (new_volume->dev_no < 2) { @@ -203,55 +212,15 @@ errno_t hr_raid0_create(hr_volume_t *new_volume) return EINVAL; } - errno_t rc; - size_t i, bsize, last_bsize; - uint64_t nblocks, last_nblocks; - uint64_t total_blocks = 0; - - rc = hr_init_devs(new_volume); - if (rc != EOK) - return rc; - - for (i = 0; i < new_volume->dev_no; i++) { - rc = block_get_nblocks(new_volume->devs[i], &nblocks); - if (rc != EOK) - goto error; - if (i != 0 && nblocks != last_nblocks) { - log_msg(LOG_DEFAULT, LVL_ERROR, - "number of blocks differs"); - rc = EINVAL; - goto error; - } - total_blocks += nblocks; - last_nblocks = nblocks; - } - - for (i = 0; i < new_volume->dev_no; i++) { - rc = block_get_bsize(new_volume->devs[i], &bsize); - if (rc != EOK) - goto error; - if (i != 0 && bsize != last_bsize) { - log_msg(LOG_DEFAULT, LVL_ERROR, "block sizes differ"); - rc = EINVAL; - goto error; - } - last_bsize = bsize; - } - bd_srvs_init(&new_volume->hr_bds); new_volume->hr_bds.ops = &hr_raid0_bd_ops; new_volume->hr_bds.sarg = new_volume; - new_volume->nblocks = total_blocks; - new_volume->bsize = bsize; rc = hr_register_volume(new_volume); if (rc != EOK) - goto error; + return rc; return EOK; -error: - hr_fini_devs(new_volume); - return rc; } /** @} diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 39ed7c98b6..267ec923c4 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -46,8 +46,8 @@ #include #include -#include "var.h" #include "util.h" +#include "var.h" extern fibril_mutex_t big_lock; extern loc_srv_t *hr_srv; @@ -84,7 +84,7 @@ static errno_t hr_raid1_bd_close(bd_srv_t *bd) return EOK; } -static errno_t hr_raid1_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t size) +static errno_t hr_raid1_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) { fibril_mutex_lock(&big_lock); hr_volume_t *vol = bd->srvs->sarg; @@ -92,8 +92,14 @@ static errno_t hr_raid1_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t size) errno_t rc; size_t i; + rc = hr_calc_ba(vol, cnt, &ba); + if (rc != EOK) { + fibril_mutex_unlock(&big_lock); + return rc; + } + for (i = 0; i < vol->dev_no; i++) { - rc = block_sync_cache(vol->devs[i], ba, size); + rc = block_sync_cache(vol->devs[i], ba, cnt); if (rc != EOK) break; } @@ -111,6 +117,12 @@ static errno_t hr_raid1_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, errno_t rc; size_t i; + rc = hr_calc_ba(vol, cnt, &ba); + if (rc != EOK) { + fibril_mutex_unlock(&big_lock); + return rc; + } + for (i = 0; i < vol->dev_no; i++) { rc = block_read_direct(vol->devs[i], ba, cnt, buf); if (rc != EOK) @@ -130,6 +142,12 @@ static errno_t hr_raid1_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, errno_t rc; size_t i; + rc = hr_calc_ba(vol, cnt, &ba); + if (rc != EOK) { + fibril_mutex_unlock(&big_lock); + return rc; + } + for (i = 0; i < vol->dev_no; i++) { rc = block_write_direct(vol->devs[i], ba, cnt, data); if (rc != EOK) @@ -152,12 +170,14 @@ static errno_t hr_raid1_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb) { hr_volume_t *vol = bd->srvs->sarg; - *rnb = vol->nblocks; + *rnb = vol->data_blkno; return EOK; } errno_t hr_raid1_create(hr_volume_t *new_volume) { + errno_t rc; + assert(new_volume->level == hr_l_1); if (new_volume->dev_no < 2) { @@ -166,55 +186,15 @@ errno_t hr_raid1_create(hr_volume_t *new_volume) return EINVAL; } - errno_t rc; - size_t i, bsize, last_bsize; - uint64_t nblocks, last_nblocks; - uint64_t total_blocks = 0; - - rc = hr_init_devs(new_volume); - if (rc != EOK) - return rc; - - for (i = 0; i < new_volume->dev_no; i++) { - rc = block_get_nblocks(new_volume->devs[i], &nblocks); - if (rc != EOK) - goto error; - if (i != 0 && nblocks != last_nblocks) { - log_msg(LOG_DEFAULT, LVL_ERROR, - "number of blocks differs"); - rc = EINVAL; - goto error; - } - total_blocks += nblocks; - last_nblocks = nblocks; - } - - for (i = 0; i < new_volume->dev_no; i++) { - rc = block_get_bsize(new_volume->devs[i], &bsize); - if (rc != EOK) - goto error; - if (i != 0 && bsize != last_bsize) { - log_msg(LOG_DEFAULT, LVL_ERROR, "block sizes differ"); - rc = EINVAL; - goto error; - } - last_bsize = bsize; - } - bd_srvs_init(&new_volume->hr_bds); new_volume->hr_bds.ops = &hr_raid1_bd_ops; new_volume->hr_bds.sarg = new_volume; - new_volume->nblocks = total_blocks / new_volume->dev_no; - new_volume->bsize = bsize; rc = hr_register_volume(new_volume); if (rc != EOK) - goto error; + return rc; return EOK; -error: - hr_fini_devs(new_volume); - return rc; } /** @} diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c new file mode 100644 index 0000000000..199835f1eb --- /dev/null +++ b/uspace/srv/bd/hr/superblock.c @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2024 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 +#include +#include + +#include "superblock.h" +#include "util.h" +#include "var.h" + +static errno_t read_metadata(service_id_t, hr_metadata_t *); + +errno_t hr_write_meta_to_vol(hr_volume_t *vol) +{ + log_msg(LOG_DEFAULT, LVL_NOTE, "hr_write_meta_to_vol()"); + + errno_t rc; + size_t i, data_offset; + uint64_t data_blkno; + hr_metadata_t *metadata; + uuid_t uuid; + + metadata = calloc(1, HR_META_SIZE * vol->bsize); + if (metadata == NULL) + return ENOMEM; + + if (vol->nblocks <= HR_META_OFF + HR_META_SIZE) { + log_msg(LOG_DEFAULT, LVL_ERROR, + "not enough blocks"); + rc = EINVAL; + goto error; + } + + data_offset = HR_META_OFF + HR_META_SIZE; + if (vol->level == hr_l_1) { + data_blkno = vol->nblocks - data_offset; + } else if (vol->level == hr_l_0) { + data_blkno = vol->nblocks - (data_offset * vol->dev_no); + } else { + log_msg(LOG_DEFAULT, LVL_ERROR, + "level %d not implemented yet", vol->level); + return EINVAL; + } + + metadata->magic = host2uint64_t_le(HR_MAGIC); + metadata->extent_no = host2uint32_t_le(vol->dev_no); + metadata->level = host2uint32_t_le(vol->level); + metadata->nblocks = host2uint64_t_le(vol->nblocks); + metadata->data_blkno = host2uint64_t_le(data_blkno); + metadata->data_offset = host2uint32_t_le(data_offset); + for (i = 0; i < vol->dev_no; i++) { + metadata->index = host2uint32_t_le(i); + + rc = uuid_generate(&uuid); + if (rc != EOK) + goto error; + uuid_encode(&uuid, metadata->uuid); + + str_cpy(metadata->devname, 32, vol->devname); + + rc = block_write_direct(vol->devs[i], HR_META_OFF, HR_META_SIZE, + metadata); + if (rc != EOK) + goto error; + } + + /* fill in new members */ + vol->data_offset = data_offset; + vol->data_blkno = data_blkno; + +error: + free(metadata); + return rc; +} + +errno_t hr_get_vol_from_meta(hr_config_t *cfg, hr_volume_t *new_volume) +{ + log_msg(LOG_DEFAULT, LVL_NOTE, "hr_get_vol_from_meta()"); + + errno_t rc; + hr_metadata_t *metadata; + + metadata = calloc(1, HR_META_SIZE * new_volume->bsize); + if (metadata == NULL) + return ENOMEM; + + /* for now assume metadata are in sync across extents */ + rc = read_metadata(cfg->devs[0], metadata); + if (rc != EOK) + goto end; + + /* TODO: sort new_volume->devs according to metadata extent index */ + + if (uint64_t_le2host(metadata->magic) != HR_MAGIC) { + printf("invalid magic\n"); + rc = EINVAL; + goto end; + } + + new_volume->level = uint32_t_le2host(metadata->level); + new_volume->dev_no = uint32_t_le2host(metadata->extent_no); + new_volume->nblocks = uint64_t_le2host(metadata->nblocks); + new_volume->data_blkno = uint64_t_le2host(metadata->data_blkno); + new_volume->data_offset = uint32_t_le2host(metadata->data_offset); + + if (str_cmp(metadata->devname, new_volume->devname) != 0) { + log_msg(LOG_DEFAULT, LVL_NOTE, + "devname on metadata (%s) and config (%s) differ, using config", + metadata->devname, new_volume->devname); + } +end: + free(metadata); + return EOK; +} + +static errno_t read_metadata(service_id_t dev, hr_metadata_t *metadata) +{ + errno_t rc; + size_t bsize; + uint64_t nblocks; + + rc = block_get_bsize(dev, &bsize); + if (rc != EOK) + return rc; + + rc = block_get_nblocks(dev, &nblocks); + if (rc != EOK) + return rc; + + if (nblocks < (HR_META_SIZE + HR_META_OFF) * bsize) + return EINVAL; + + rc = block_read_direct(dev, HR_META_OFF, HR_META_SIZE, metadata); + if (rc != EOK) + return rc; + + return EOK; +} + +/** @} + */ diff --git a/uspace/srv/bd/hr/superblock.h b/uspace/srv/bd/hr/superblock.h new file mode 100644 index 0000000000..324af72d6d --- /dev/null +++ b/uspace/srv/bd/hr/superblock.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2024 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 + */ + +#ifndef _HR_SUPERBLOCK_H +#define _HR_SUPERBLOCK_H + +#include "var.h" + +#define HR_MAGIC 0x4420492041205248LLU + +typedef struct hr_metadata { + uint64_t magic; + uint32_t extent_no; + uint32_t level; + uint64_t nblocks; /* all blocks */ + uint64_t data_blkno; /* usable blocks */ + uint32_t data_offset; /* block where data starts */ + uint32_t index; /* index of disk in array */ + uint8_t uuid[16]; + char devname[32]; +} hr_metadata_t; + +#define HR_META_SIZE 1 /* in blocks */ +#define HR_META_OFF 8 /* in blocks */ + +extern errno_t hr_write_meta_to_vol(hr_volume_t *); +extern errno_t hr_get_vol_from_meta(hr_config_t *, hr_volume_t *); + +#endif + +/** @} + */ diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index ea8aaf9ce0..45a48da061 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -42,8 +42,8 @@ #include #include -#include "var.h" #include "util.h" +#include "var.h" extern loc_srv_t *hr_srv; @@ -81,6 +81,8 @@ void hr_fini_devs(hr_volume_t *vol) errno_t hr_register_volume(hr_volume_t *new_volume) { + log_msg(LOG_DEFAULT, LVL_NOTE, "hr_register_volume()"); + errno_t rc; service_id_t new_id; category_id_t cat_id; @@ -119,5 +121,64 @@ errno_t hr_register_volume(hr_volume_t *new_volume) return rc; } +errno_t hr_check_devs(hr_volume_t *vol) +{ + log_msg(LOG_DEFAULT, LVL_NOTE, "hr_check_devs()"); + + errno_t rc; + size_t i, bsize, last_bsize; + uint64_t nblocks, last_nblocks; + uint64_t total_blocks = 0; + + for (i = 0; i < vol->dev_no; i++) { + rc = block_get_nblocks(vol->devs[i], &nblocks); + if (rc != EOK) + goto error; + if (i != 0 && nblocks != last_nblocks) { + log_msg(LOG_DEFAULT, LVL_ERROR, + "number of blocks differs"); + rc = EINVAL; + goto error; + } + total_blocks += nblocks; + last_nblocks = nblocks; + } + + for (i = 0; i < vol->dev_no; i++) { + rc = block_get_bsize(vol->devs[i], &bsize); + if (rc != EOK) + goto error; + if (i != 0 && bsize != last_bsize) { + log_msg(LOG_DEFAULT, LVL_ERROR, "block sizes differ"); + rc = EINVAL; + goto error; + } + last_bsize = bsize; + } + + if (vol->level == hr_l_1) { + vol->nblocks = total_blocks / vol->dev_no; + } else if (vol->level == hr_l_0) { + vol->nblocks = total_blocks; + } else { + log_msg(LOG_DEFAULT, LVL_DEBUG, "unkown level, ok when assembling"); + vol->nblocks = 0; + } + + vol->bsize = bsize; + +error: + return rc; +} + +errno_t hr_calc_ba(hr_volume_t *vol, size_t cnt, uint64_t *ba) +{ + if (*ba + cnt > vol->data_blkno) + return ERANGE; + + *ba = *ba + vol->data_offset; + return EOK; +} + /** @} */ diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index 3635371639..18aa2a49e2 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -43,6 +43,8 @@ extern errno_t hr_init_devs(hr_volume_t *); extern void hr_fini_devs(hr_volume_t *); extern errno_t hr_register_volume(hr_volume_t *); +extern errno_t hr_check_devs(hr_volume_t *vol); +errno_t hr_calc_ba(hr_volume_t *vol, size_t cnt, uint64_t *ba); #endif diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index befa9c9945..32d0d59acf 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -42,6 +42,8 @@ #define NAME "hr" +#define HR_STRIP_SIZE DATA_XFER_LIMIT + typedef struct hr_volume hr_volume_t; typedef struct hr_ops { @@ -55,8 +57,10 @@ typedef struct hr_volume { char devname[32]; service_id_t devs[HR_MAXDEVS]; uint64_t nblocks; - size_t bsize; + uint64_t data_blkno; + uint32_t data_offset; service_id_t svc_id; + size_t bsize; size_t dev_no; hr_level_t level; } hr_volume_t; From 9c1cf34ca174ca5c556454d53f3356c6c4b957e0 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 6 Sep 2024 14:14:09 +0200 Subject: [PATCH 015/324] hr: add strip size to metadata and hr_volume_t --- uspace/lib/device/include/hr.h | 1 + uspace/lib/device/src/hr.c | 15 +++++++++++++-- uspace/srv/bd/hr/hr.c | 12 +++++++----- uspace/srv/bd/hr/raid0.c | 2 +- uspace/srv/bd/hr/superblock.c | 2 ++ uspace/srv/bd/hr/superblock.h | 2 ++ uspace/srv/bd/hr/var.h | 1 + 7 files changed, 27 insertions(+), 8 deletions(-) diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index cfa48a9501..2a31e365bb 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -68,6 +68,7 @@ typedef struct hr_vol_info { service_id_t svc_id; hr_level_t level; uint64_t nblocks; + uint32_t strip_size; size_t bsize; } hr_vol_info_t; diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index f3be2578a8..f560f0b5c0 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -156,8 +156,19 @@ static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info) printf("devname: %s\n", devname); printf("level: %d\n", vol_info->level); - printf("nblocks: %lu\n", vol_info->nblocks); - printf("bsize: %zu\n", vol_info->bsize); + if (vol_info->level == hr_l_0) { + if (vol_info->strip_size / 1024 < 1) + printf("strip size in bytes: %u\n", + vol_info->strip_size); + else + printf("strip size: %uK\n", + vol_info->strip_size / 1024); + } + printf("size in bytes: %luMiB\n", + vol_info->nblocks * vol_info->bsize / 1024 / 1024); + printf("size in blocks: %lu\n", vol_info->nblocks); + printf("block size: %zu\n", vol_info->bsize); + printf("extents: [index] [devname]\n"); for (i = 0; i < vol_info->extent_no; i++) { diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 3d0635a2e9..c68dbf90d0 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -60,7 +60,6 @@ static list_t hr_volumes; static service_id_t ctl_sid; - static void hr_create_srv(ipc_call_t *icall) { log_msg(LOG_DEFAULT, LVL_NOTE, "hr_create_srv()"); @@ -120,16 +119,14 @@ static void hr_create_srv(ipc_call_t *icall) if (rc != EOK) goto error; - rc = hr_write_meta_to_vol(new_volume); - if (rc != EOK) - goto error; - switch (new_volume->level) { case hr_l_1: new_volume->hr_ops.create = hr_raid1_create; + new_volume->strip_size = 0; break; case hr_l_0: new_volume->hr_ops.create = hr_raid0_create; + new_volume->strip_size = HR_STRIP_SIZE; break; default: log_msg(LOG_DEFAULT, LVL_ERROR, @@ -138,6 +135,10 @@ static void hr_create_srv(ipc_call_t *icall) goto error; } + rc = hr_write_meta_to_vol(new_volume); + if (rc != EOK) + goto error; + rc = new_volume->hr_ops.create(new_volume); if (rc != EOK) goto error; @@ -296,6 +297,7 @@ static void hr_print_status_srv(ipc_call_t *icall) info.level = volume->level; /* print usable number of blocks */ info.nblocks = volume->data_blkno; + info.strip_size = volume->strip_size; info.bsize = volume->bsize; if (!async_data_read_receive(&call, &size)) { diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index 3f0bcd5f46..3f42227456 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -77,7 +77,7 @@ static void raid0_geometry(uint64_t x, hr_volume_t *vol, size_t *extent, uint64_t *phys_block) { uint64_t N = vol->dev_no; /* extents */ - uint64_t L = HR_STRIP_SIZE / vol->bsize; /* size of strip in blocks */ + uint64_t L = vol->strip_size / vol->bsize; /* size of strip in blocks */ uint64_t i = (x / L) % N; /* extent */ uint64_t j = (x / L) / N; /* stripe */ diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index 199835f1eb..b400f281a2 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -89,6 +89,7 @@ errno_t hr_write_meta_to_vol(hr_volume_t *vol) metadata->nblocks = host2uint64_t_le(vol->nblocks); metadata->data_blkno = host2uint64_t_le(data_blkno); metadata->data_offset = host2uint32_t_le(data_offset); + metadata->strip_size = host2uint32_t_le(vol->strip_size); for (i = 0; i < vol->dev_no; i++) { metadata->index = host2uint32_t_le(i); @@ -143,6 +144,7 @@ errno_t hr_get_vol_from_meta(hr_config_t *cfg, hr_volume_t *new_volume) new_volume->nblocks = uint64_t_le2host(metadata->nblocks); new_volume->data_blkno = uint64_t_le2host(metadata->data_blkno); new_volume->data_offset = uint32_t_le2host(metadata->data_offset); + new_volume->strip_size = uint32_t_le2host(metadata->strip_size); if (str_cmp(metadata->devname, new_volume->devname) != 0) { log_msg(LOG_DEFAULT, LVL_NOTE, diff --git a/uspace/srv/bd/hr/superblock.h b/uspace/srv/bd/hr/superblock.h index 324af72d6d..77657cb7c7 100644 --- a/uspace/srv/bd/hr/superblock.h +++ b/uspace/srv/bd/hr/superblock.h @@ -48,6 +48,8 @@ typedef struct hr_metadata { uint64_t data_blkno; /* usable blocks */ uint32_t data_offset; /* block where data starts */ uint32_t index; /* index of disk in array */ + uint32_t strip_size; + uint32_t status; /* yet unused */ uint8_t uuid[16]; char devname[32]; } hr_metadata_t; diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index 32d0d59acf..3af5444133 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -59,6 +59,7 @@ typedef struct hr_volume { uint64_t nblocks; uint64_t data_blkno; uint32_t data_offset; + uint32_t strip_size; service_id_t svc_id; size_t bsize; size_t dev_no; From 24968b54fa9a3fd2c64b003f54e8a75a9145cee7 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 6 Sep 2024 14:15:06 +0200 Subject: [PATCH 016/324] hr: assemble: check specified number of devices against metadata --- uspace/srv/bd/hr/superblock.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index b400f281a2..0bf10f789d 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -146,6 +146,14 @@ errno_t hr_get_vol_from_meta(hr_config_t *cfg, hr_volume_t *new_volume) new_volume->data_offset = uint32_t_le2host(metadata->data_offset); new_volume->strip_size = uint32_t_le2host(metadata->strip_size); + if (new_volume->dev_no != cfg->dev_no) { + log_msg(LOG_DEFAULT, LVL_ERROR, + "number of divices in array differ: specified %zu, metadata states %zu", + cfg->dev_no, new_volume->dev_no); + rc = EINVAL; + goto end; + } + if (str_cmp(metadata->devname, new_volume->devname) != 0) { log_msg(LOG_DEFAULT, LVL_NOTE, "devname on metadata (%s) and config (%s) differ, using config", @@ -153,7 +161,7 @@ errno_t hr_get_vol_from_meta(hr_config_t *cfg, hr_volume_t *new_volume) } end: free(metadata); - return EOK; + return rc; } static errno_t read_metadata(service_id_t dev, hr_metadata_t *metadata) From ab5a25977843a097fb7c0687f6bab49005fc16f1 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 6 Sep 2024 14:51:48 +0200 Subject: [PATCH 017/324] bdwrite: writing to block devices --- uspace/app/bdwrite/bdwrite.c | 129 +++++++++++++++++++++++++++++++++ uspace/app/bdwrite/meson.build | 30 ++++++++ uspace/app/meson.build | 1 + 3 files changed, 160 insertions(+) create mode 100644 uspace/app/bdwrite/bdwrite.c create mode 100644 uspace/app/bdwrite/meson.build diff --git a/uspace/app/bdwrite/bdwrite.c b/uspace/app/bdwrite/bdwrite.c new file mode 100644 index 0000000000..4ded5d2e04 --- /dev/null +++ b/uspace/app/bdwrite/bdwrite.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2024 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 bdwrite + * @{ + */ +/** + * @file + */ + +#include +#include +#include +#include +#include +#include + +static void usage(void); + +static const char usage_str[] = + "Usage: bdwrite -o -c \n" + "\n" + " Write cyclic blocks to block device.\n"; + +static struct option const long_options[] = { + { 0, 0, 0, 0 } +}; + +static void usage(void) +{ + printf("%s", usage_str); +} + +int main(int argc, char **argv) +{ + errno_t rc; + size_t bsize; + int c; + char *name = NULL; + size_t blkcnt = 0, off = 0; + service_id_t dev; + + if (argc != 6) { + goto bad; + } + + name = argv[1]; + + c = 0; + optreset = 1; + optind = 0; + + while (c != -1) { + c = getopt_long(argc, argv, "o:c:", long_options, NULL); + switch (c) { + case 'o': + off = strtol(optarg, NULL, 10); + break; + case 'c': + blkcnt = strtol(optarg, NULL, 10); + break; + } + } + + rc = loc_service_get_id(name, &dev, 0); + if (rc != EOK) { + printf("bdwrite: error resolving device \"%s\"\n", name); + return 1; + } + rc = block_init(dev); + if (rc != EOK) { + printf("bdwrite: error initializing block device \"%s\"\n", name); + return 1; + } + + rc = block_get_bsize(dev, &bsize); + if (rc != EOK) { + printf("bdwrite: error getting block size of \"%s\"\n", name); + block_fini(dev); + return 1; + } + + uint8_t *buf = calloc(1, bsize); + for (size_t i = 0; i < blkcnt; i++) { + memset(buf, (i + 1) % 0x100, bsize); + rc = block_write_direct(dev, i + off, 1, buf); + if (rc != EOK) { + printf("bdwrite: error writing to \"%s\"\n", name); + free(buf); + block_fini(dev); + return 1; + } + } + + free(buf); + block_fini(dev); + return 0; +bad: + usage(); + return 0; +} + +/** @} + */ diff --git a/uspace/app/bdwrite/meson.build b/uspace/app/bdwrite/meson.build new file mode 100644 index 0000000000..faa14ed30e --- /dev/null +++ b/uspace/app/bdwrite/meson.build @@ -0,0 +1,30 @@ +# +# Copyright (c) 2024 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. +# + +deps = [ 'block' ] +src = files('bdwrite.c') diff --git a/uspace/app/meson.build b/uspace/app/meson.build index 51f22e8f0b..c5f44af601 100644 --- a/uspace/app/meson.build +++ b/uspace/app/meson.build @@ -30,6 +30,7 @@ apps = [ 'aboutos', 'barber', 'bdsh', + 'bdwrite', 'bithenge', 'blkdump', 'calculator', From 09398589f86c171d008fdf8c9ef18c4f9efb07f7 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 6 Sep 2024 14:53:38 +0200 Subject: [PATCH 018/324] hr: cstyle: remove redundant space --- uspace/lib/device/src/hr.c | 1 - 1 file changed, 1 deletion(-) diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index f560f0b5c0..30103decd9 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -169,7 +169,6 @@ static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info) printf("size in blocks: %lu\n", vol_info->nblocks); printf("block size: %zu\n", vol_info->bsize); - printf("extents: [index] [devname]\n"); for (i = 0; i < vol_info->extent_no; i++) { rc = loc_service_get_name(vol_info->extents[i], &devname); From a19d7fc4b9a9e9429e475bb951803a662991726d Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 6 Sep 2024 16:54:21 +0200 Subject: [PATCH 019/324] hr: add option (-T, --stop) for removing an active array --- uspace/app/hrctl/hrctl.c | 9 ++- uspace/lib/device/include/hr.h | 1 + uspace/lib/device/include/ipc/hr.h | 1 + uspace/lib/device/src/hr.c | 45 +++++++++++++-- uspace/srv/bd/hr/hr.c | 90 +++++++++++++++++++++++------- 5 files changed, 121 insertions(+), 25 deletions(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index ab8436a83b..53de9b4572 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -85,6 +85,7 @@ static struct option const long_options[] = { { "level", required_argument, 0, 'l' }, { "create-file", required_argument, 0, 'C' }, { "assemble-file", required_argument, 0, 'A' }, + { "stop", required_argument, 0, 'T' }, { 0, 0, 0, 0 } }; @@ -230,7 +231,7 @@ int main(int argc, char **argv) optind = 0; while (c != -1) { - c = getopt_long(argc, argv, "hsC:c:A:a:l:015Ln:", + c = getopt_long(argc, argv, "hsC:c:A:a:l:015Ln:T:", long_options, NULL); switch (c) { case 'h': @@ -274,6 +275,12 @@ int main(int argc, char **argv) str_cpy(cfg->devname, sizeof(cfg->devname), optarg); assemble = true; break; + case 'T': + rc = hr_stop(optarg); + free(cfg); + if (rc != EOK) + return 1; + return 0; case 'l': if (cfg->level != hr_l_empty) goto bad; diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index 2a31e365bb..a09a9b9248 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -77,6 +77,7 @@ extern void hr_sess_destroy(hr_t *); extern errno_t hr_create(hr_t *, hr_config_t *); extern errno_t hr_assemble(hr_t *, hr_config_t *); +extern errno_t hr_stop(const char *); extern errno_t hr_print_status(void); #endif diff --git a/uspace/lib/device/include/ipc/hr.h b/uspace/lib/device/include/ipc/hr.h index cd535bf40d..694b461600 100644 --- a/uspace/lib/device/include/ipc/hr.h +++ b/uspace/lib/device/include/ipc/hr.h @@ -40,6 +40,7 @@ typedef enum { HR_CREATE = IPC_FIRST_USER_METHOD, HR_ASSEMBLE, + HR_STOP, HR_STATUS } hr_request_t; diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index 30103decd9..d1182cb189 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -179,6 +179,36 @@ static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info) return EOK; } +errno_t hr_stop(const char *devname) +{ + hr_t *hr; + errno_t rc; + async_exch_t *exch; + service_id_t svc_id; + + rc = loc_service_get_id(devname, &svc_id, 0); + if (rc != EOK) + return rc; + + rc = hr_sess_init(&hr); + if (rc != EOK) + return rc; + + exch = async_exchange_begin(hr->sess); + if (exch == NULL) { + rc = EINVAL; + goto error; + } + rc = async_req_1_0(exch, HR_STOP, svc_id); + async_exchange_end(exch); + + if (rc != EOK) + goto error; +error: + hr_sess_destroy(hr); + return rc; +} + errno_t hr_print_status(void) { hr_t *hr; @@ -186,18 +216,19 @@ errno_t hr_print_status(void) async_exch_t *exch; aid_t req; size_t size, i; - hr_vol_info_t *vols; + hr_vol_info_t *vols = NULL; rc = hr_sess_init(&hr); if (rc != EOK) return rc; exch = async_exchange_begin(hr->sess); - if (exch == NULL) - return EINVAL; + if (exch == NULL) { + rc = EINVAL; + goto error; + } req = async_send_0(exch, HR_STATUS, NULL); - rc = async_data_read_start(exch, &size, sizeof(size_t)); if (rc != EOK) { async_exchange_end(exch); @@ -229,6 +260,11 @@ errno_t hr_print_status(void) goto error; } + if (size == 0) { + printf("no active arrays\n"); + goto error; + } + for (i = 0; i < size; i++) { rc = print_vol_info(i, &vols[i]); if (rc != EOK) @@ -236,6 +272,7 @@ errno_t hr_print_status(void) } error: + hr_sess_destroy(hr); if (vols != NULL) free(vols); return rc; diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index c68dbf90d0..91c8eb5764 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -60,6 +60,43 @@ static list_t hr_volumes; static service_id_t ctl_sid; +static hr_volume_t *hr_get_volume(service_id_t svc_id) +{ + log_msg(LOG_DEFAULT, LVL_DEBUG, "hr_get_volume(): (%" PRIun ")", + svc_id); + + fibril_mutex_lock(&hr_volumes_lock); + list_foreach(hr_volumes, lvolumes, hr_volume_t, volume) { + if (volume->svc_id == svc_id) { + fibril_mutex_unlock(&hr_volumes_lock); + return volume; + } + } + + fibril_mutex_unlock(&hr_volumes_lock); + return NULL; +} + +static errno_t hr_remove_volume(service_id_t svc_id) +{ + log_msg(LOG_DEFAULT, LVL_DEBUG, "hr_remove_volume(): (%" PRIun ")", + svc_id); + + fibril_mutex_lock(&hr_volumes_lock); + list_foreach(hr_volumes, lvolumes, hr_volume_t, volume) { + if (volume->svc_id == svc_id) { + hr_fini_devs(volume); + list_remove(&volume->lvolumes); + free(volume); + fibril_mutex_unlock(&hr_volumes_lock); + return EOK; + } + } + + fibril_mutex_unlock(&hr_volumes_lock); + return ENOENT; +} + static void hr_create_srv(ipc_call_t *icall) { log_msg(LOG_DEFAULT, LVL_NOTE, "hr_create_srv()"); @@ -261,6 +298,33 @@ static void hr_assemble_srv(ipc_call_t *icall) async_answer_0(icall, rc); } +static void hr_stop_srv(ipc_call_t *icall) +{ + log_msg(LOG_DEFAULT, LVL_NOTE, "hr_stop_srv()"); + + errno_t rc; + service_id_t svc_id; + hr_volume_t *vol; + + svc_id = ipc_get_arg1(icall); + + vol = hr_get_volume(svc_id); + if (vol == NULL) { + async_answer_0(icall, ENOENT); + return; + } + + rc = hr_remove_volume(svc_id); + if (rc != EOK) { + async_answer_0(icall, rc); + return; + } + + rc = loc_service_unregister(hr_srv, svc_id); + + async_answer_0(icall, rc); +} + static void hr_print_status_srv(ipc_call_t *icall) { log_msg(LOG_DEFAULT, LVL_NOTE, "hr_status_srv()"); @@ -344,35 +408,21 @@ static void hr_ctl_conn(ipc_call_t *icall, void *arg) case HR_CREATE: hr_create_srv(&call); break; - case HR_STATUS: - hr_print_status_srv(&call); - break; case HR_ASSEMBLE: hr_assemble_srv(&call); break; + case HR_STOP: + hr_stop_srv(&call); + break; + case HR_STATUS: + hr_print_status_srv(&call); + break; default: async_answer_0(&call, EINVAL); } } } -static hr_volume_t *hr_get_volume(service_id_t svc_id) -{ - log_msg(LOG_DEFAULT, LVL_DEBUG, "hr_get_volume(): (%" PRIun ")", - svc_id); - - fibril_mutex_lock(&hr_volumes_lock); - list_foreach(hr_volumes, lvolumes, hr_volume_t, volume) { - if (volume->svc_id == svc_id) { - fibril_mutex_unlock(&hr_volumes_lock); - return volume; - } - } - - fibril_mutex_unlock(&hr_volumes_lock); - return NULL; -} - static void hr_client_conn(ipc_call_t *icall, void *arg) { log_msg(LOG_DEFAULT, LVL_NOTE, "hr_client_conn()"); From 4a2a6b8b9267feafb10763f60d2b4685bb8bbf67 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sat, 7 Sep 2024 00:09:33 +0200 Subject: [PATCH 020/324] hr: add initial RAID 4 0 (non-rotating parity on disk 0) --- uspace/app/hrctl/hrctl.c | 7 +- uspace/lib/device/include/hr.h | 1 + uspace/lib/device/src/hr.c | 2 +- uspace/srv/bd/hr/hr.c | 7 + uspace/srv/bd/hr/meson.build | 2 +- uspace/srv/bd/hr/raid0.c | 45 +++--- uspace/srv/bd/hr/raid1.c | 33 ++-- uspace/srv/bd/hr/raid4.c | 285 +++++++++++++++++++++++++++++++++ uspace/srv/bd/hr/superblock.c | 2 + uspace/srv/bd/hr/util.c | 11 +- uspace/srv/bd/hr/util.h | 3 +- uspace/srv/bd/hr/var.h | 1 + 12 files changed, 358 insertions(+), 41 deletions(-) create mode 100644 uspace/srv/bd/hr/raid4.c diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index 53de9b4572..7644e5df32 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -231,7 +231,7 @@ int main(int argc, char **argv) optind = 0; while (c != -1) { - c = getopt_long(argc, argv, "hsC:c:A:a:l:015Ln:T:", + c = getopt_long(argc, argv, "hsC:c:A:a:l:0145Ln:T:", long_options, NULL); switch (c) { case 'h': @@ -299,6 +299,11 @@ int main(int argc, char **argv) goto bad; cfg->level = hr_l_1; break; + case '4': + if (cfg->level != hr_l_empty) + goto bad; + cfg->level = hr_l_4; + break; case '5': if (cfg->level != hr_l_empty) goto bad; diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index a09a9b9248..4ed60ad98d 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -50,6 +50,7 @@ typedef struct hr { typedef enum hr_level { hr_l_0 = 0, hr_l_1 = 1, + hr_l_4 = 4, hr_l_5 = 5, hr_l_linear = 254, hr_l_empty = 255 diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index d1182cb189..a149597c63 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -156,7 +156,7 @@ static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info) printf("devname: %s\n", devname); printf("level: %d\n", vol_info->level); - if (vol_info->level == hr_l_0) { + if (vol_info->level == hr_l_0 || vol_info->level == hr_l_4) { if (vol_info->strip_size / 1024 < 1) printf("strip size in bytes: %u\n", vol_info->strip_size); diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 91c8eb5764..30d7091270 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -165,6 +165,10 @@ static void hr_create_srv(ipc_call_t *icall) new_volume->hr_ops.create = hr_raid0_create; new_volume->strip_size = HR_STRIP_SIZE; break; + case hr_l_4: + new_volume->hr_ops.create = hr_raid4_create; + new_volume->strip_size = HR_STRIP_SIZE; + break; default: log_msg(LOG_DEFAULT, LVL_ERROR, "level %d not implemented yet", new_volume->level); @@ -271,6 +275,9 @@ static void hr_assemble_srv(ipc_call_t *icall) case hr_l_0: new_volume->hr_ops.create = hr_raid0_create; break; + case hr_l_4: + new_volume->hr_ops.create = hr_raid4_create; + break; default: log_msg(LOG_DEFAULT, LVL_ERROR, "level %d not implemented yet", new_volume->level); diff --git a/uspace/srv/bd/hr/meson.build b/uspace/srv/bd/hr/meson.build index 29b673d98c..250f9c853a 100644 --- a/uspace/srv/bd/hr/meson.build +++ b/uspace/srv/bd/hr/meson.build @@ -27,4 +27,4 @@ # deps = [ 'block', 'device' ] -src = files('hr.c', 'raid0.c', 'raid1.c', 'superblock.c', 'util.c') +src = files('hr.c', 'raid0.c', 'raid1.c', 'raid4.c', 'superblock.c', 'util.c') diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index 3f42227456..bdd8b2a7a3 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -104,20 +104,23 @@ static errno_t hr_raid0_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) hr_volume_t *vol = bd->srvs->sarg; errno_t rc; uint64_t phys_block; - size_t extent; + size_t extent, left; + + rc = hr_check_ba_range(vol, cnt, ba); + if (rc != EOK) + return rc; fibril_mutex_lock(&big_lock); - size_t left = cnt; + left = cnt; while (left != 0) { - raid0_geometry(ba++, vol, &extent, &phys_block); - rc = hr_calc_ba(vol, cnt, &ba); - if (rc != EOK) - break; + raid0_geometry(ba, vol, &extent, &phys_block); + hr_add_ba_offset(vol, &phys_block); rc = block_sync_cache(vol->devs[extent], phys_block, 1); if (rc != EOK) break; left--; + ba++; } fibril_mutex_unlock(&big_lock); @@ -130,24 +133,27 @@ static errno_t hr_raid0_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, hr_volume_t *vol = bd->srvs->sarg; errno_t rc; uint64_t phys_block; - size_t extent; + size_t extent, left; if (size < cnt * vol->bsize) return EINVAL; + rc = hr_check_ba_range(vol, cnt, ba); + if (rc != EOK) + return rc; + fibril_mutex_lock(&big_lock); - size_t left = cnt; + left = cnt; while (left != 0) { - raid0_geometry(ba++, vol, &extent, &phys_block); - rc = hr_calc_ba(vol, cnt, &ba); - if (rc != EOK) - break; + raid0_geometry(ba, vol, &extent, &phys_block); + hr_add_ba_offset(vol, &phys_block); rc = block_read_direct(vol->devs[extent], phys_block, 1, buf); buf = buf + vol->bsize; if (rc != EOK) break; left--; + ba++; } fibril_mutex_unlock(&big_lock); @@ -160,24 +166,27 @@ static errno_t hr_raid0_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, hr_volume_t *vol = bd->srvs->sarg; errno_t rc; uint64_t phys_block; - size_t extent; + size_t extent, left; if (size < cnt * vol->bsize) return EINVAL; + rc = hr_check_ba_range(vol, cnt, ba); + if (rc != EOK) + return rc; + fibril_mutex_lock(&big_lock); - size_t left = cnt; + left = cnt; while (left != 0) { - raid0_geometry(ba++, vol, &extent, &phys_block); - rc = hr_calc_ba(vol, cnt, &phys_block); - if (rc != EOK) - break; + raid0_geometry(ba, vol, &extent, &phys_block); + hr_add_ba_offset(vol, &phys_block); rc = block_write_direct(vol->devs[extent], phys_block, 1, data); data = data + vol->bsize; if (rc != EOK) break; left--; + ba++; } fibril_mutex_unlock(&big_lock); diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 267ec923c4..6cfd247b18 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -86,17 +86,18 @@ static errno_t hr_raid1_bd_close(bd_srv_t *bd) static errno_t hr_raid1_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) { - fibril_mutex_lock(&big_lock); hr_volume_t *vol = bd->srvs->sarg; errno_t rc; size_t i; - rc = hr_calc_ba(vol, cnt, &ba); - if (rc != EOK) { - fibril_mutex_unlock(&big_lock); + rc = hr_check_ba_range(vol, cnt, ba); + if (rc != EOK) return rc; - } + + hr_add_ba_offset(vol, &ba); + + fibril_mutex_lock(&big_lock); for (i = 0; i < vol->dev_no; i++) { rc = block_sync_cache(vol->devs[i], ba, cnt); @@ -111,17 +112,18 @@ static errno_t hr_raid1_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) static errno_t hr_raid1_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, void *buf, size_t size) { - fibril_mutex_lock(&big_lock); hr_volume_t *vol = bd->srvs->sarg; errno_t rc; size_t i; - rc = hr_calc_ba(vol, cnt, &ba); - if (rc != EOK) { - fibril_mutex_unlock(&big_lock); + rc = hr_check_ba_range(vol, cnt, ba); + if (rc != EOK) return rc; - } + + hr_add_ba_offset(vol, &ba); + + fibril_mutex_lock(&big_lock); for (i = 0; i < vol->dev_no; i++) { rc = block_read_direct(vol->devs[i], ba, cnt, buf); @@ -136,17 +138,18 @@ static errno_t hr_raid1_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, static errno_t hr_raid1_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, const void *data, size_t size) { - fibril_mutex_lock(&big_lock); hr_volume_t *vol = bd->srvs->sarg; errno_t rc; size_t i; - rc = hr_calc_ba(vol, cnt, &ba); - if (rc != EOK) { - fibril_mutex_unlock(&big_lock); + rc = hr_check_ba_range(vol, cnt, ba); + if (rc != EOK) return rc; - } + + hr_add_ba_offset(vol, &ba); + + fibril_mutex_lock(&big_lock); for (i = 0; i < vol->dev_no; i++) { rc = block_write_direct(vol->devs[i], ba, cnt, data); diff --git a/uspace/srv/bd/hr/raid4.c b/uspace/srv/bd/hr/raid4.c new file mode 100644 index 0000000000..2ec825c0fa --- /dev/null +++ b/uspace/srv/bd/hr/raid4.c @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2024 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 +#include +#include +#include +#include + +#include "util.h" +#include "var.h" + +extern fibril_mutex_t big_lock; +extern loc_srv_t *hr_srv; + +static errno_t hr_raid4_bd_open(bd_srvs_t *, bd_srv_t *); +static errno_t hr_raid4_bd_close(bd_srv_t *); +static errno_t hr_raid4_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, + size_t); +static errno_t hr_raid4_bd_sync_cache(bd_srv_t *, aoff64_t, size_t); +static errno_t hr_raid4_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, + const void *, size_t); +static errno_t hr_raid4_bd_get_block_size(bd_srv_t *, size_t *); +static errno_t hr_raid4_bd_get_num_blocks(bd_srv_t *, aoff64_t *); + +static bd_ops_t hr_raid4_bd_ops = { + .open = hr_raid4_bd_open, + .close = hr_raid4_bd_close, + .sync_cache = hr_raid4_bd_sync_cache, + .read_blocks = hr_raid4_bd_read_blocks, + .write_blocks = hr_raid4_bd_write_blocks, + .get_block_size = hr_raid4_bd_get_block_size, + .get_num_blocks = hr_raid4_bd_get_num_blocks +}; + +static void xor(void *dst, const void *src, size_t size) +{ + size_t i; + uint64_t *d = dst; + const uint64_t *s = src; + + for (i = 0; i < size / sizeof(uint64_t); ++i) + *d++ ^= *s++; +} + +static errno_t write_parity(hr_volume_t *vol, uint64_t extent, uint64_t block, + const void *data) +{ + errno_t rc; + size_t i; + void *xorbuf; + void *buf; + + xorbuf = calloc(1, vol->bsize); + if (xorbuf == NULL) + return ENOMEM; + + buf = malloc(vol->bsize); + if (buf == NULL) + return ENOMEM; + + for (i = 1; i < vol->dev_no; i++) { + if (i == extent) { + xor(xorbuf, data, vol->bsize); + } else { + rc = block_read_direct(vol->devs[i], block, 1, buf); + if (rc != EOK) + goto end; + xor(xorbuf, buf, vol->bsize); + } + } + + rc = block_write_direct(vol->devs[0], block, 1, xorbuf); + +end: + free(xorbuf); + free(buf); + return EOK; +} + +static void raid4_geometry(uint64_t x, hr_volume_t *vol, size_t *extent, + uint64_t *phys_block) +{ + uint64_t N = vol->dev_no; /* extents */ + uint64_t L = vol->strip_size / vol->bsize; /* size of strip in blocks */ + + uint64_t i = ((x / L) % (N - 1)) + 1; /* extent */ + uint64_t j = (x / L) / (N - 1); /* stripe */ + uint64_t k = x % L; /* strip offset */ + + *extent = i; + *phys_block = j * L + k; +} + +static errno_t hr_raid4_bd_open(bd_srvs_t *bds, bd_srv_t *bd) +{ + log_msg(LOG_DEFAULT, LVL_NOTE, "hr_bd_open()"); + return EOK; +} + +static errno_t hr_raid4_bd_close(bd_srv_t *bd) +{ + log_msg(LOG_DEFAULT, LVL_NOTE, "hr_bd_close()"); + return EOK; +} + +static errno_t hr_raid4_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) +{ + hr_volume_t *vol = bd->srvs->sarg; + errno_t rc; + uint64_t phys_block; + size_t extent; + + rc = hr_check_ba_range(vol, cnt, ba); + if (rc != EOK) + return rc; + + fibril_mutex_lock(&big_lock); + + size_t left = cnt; + while (left != 0) { + raid4_geometry(ba, vol, &extent, &phys_block); + hr_add_ba_offset(vol, &phys_block); + rc = block_sync_cache(vol->devs[extent], phys_block, 1); + if (rc != EOK) + break; + left--; + ba++; + } + + fibril_mutex_unlock(&big_lock); + return rc; +} + +static errno_t hr_raid4_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, + void *buf, size_t size) +{ + hr_volume_t *vol = bd->srvs->sarg; + errno_t rc; + uint64_t phys_block; + size_t extent; + + if (size < cnt * vol->bsize) + return EINVAL; + + rc = hr_check_ba_range(vol, cnt, ba); + if (rc != EOK) + return rc; + + fibril_mutex_lock(&big_lock); + + size_t left = cnt; + while (left != 0) { + raid4_geometry(ba, vol, &extent, &phys_block); + hr_add_ba_offset(vol, &phys_block); + rc = block_read_direct(vol->devs[extent], phys_block, 1, buf); + buf = buf + vol->bsize; + if (rc != EOK) + break; + left--; + ba++; + } + + fibril_mutex_unlock(&big_lock); + return rc; +} + + +static errno_t hr_raid4_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, + const void *data, size_t size) +{ + hr_volume_t *vol = bd->srvs->sarg; + errno_t rc; + uint64_t phys_block; + size_t extent; + + if (size < cnt * vol->bsize) + return EINVAL; + + rc = hr_check_ba_range(vol, cnt, ba); + if (rc != EOK) + return rc; + + fibril_mutex_lock(&big_lock); + + size_t left = cnt; + while (left != 0) { + raid4_geometry(ba, vol, &extent, &phys_block); + hr_add_ba_offset(vol, &phys_block); + rc = block_write_direct(vol->devs[extent], phys_block, 1, data); + if (rc != EOK) + break; + rc = write_parity(vol, extent, phys_block, data); + if (rc != EOK) + break; + data = data + vol->bsize; + left--; + ba++; + } + + fibril_mutex_unlock(&big_lock); + return rc; +} + +static errno_t hr_raid4_bd_get_block_size(bd_srv_t *bd, size_t *rsize) +{ + hr_volume_t *vol = bd->srvs->sarg; + + *rsize = vol->bsize; + return EOK; +} + +static errno_t hr_raid4_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb) +{ + hr_volume_t *vol = bd->srvs->sarg; + + *rnb = vol->data_blkno; + return EOK; +} + +errno_t hr_raid4_create(hr_volume_t *new_volume) +{ + errno_t rc; + + assert(new_volume->level == hr_l_4); + + if (new_volume->dev_no < 3) { + log_msg(LOG_DEFAULT, LVL_ERROR, + "RAID 4 array needs at least 3 devices"); + return EINVAL; + } + + bd_srvs_init(&new_volume->hr_bds); + new_volume->hr_bds.ops = &hr_raid4_bd_ops; + new_volume->hr_bds.sarg = new_volume; + + rc = hr_register_volume(new_volume); + if (rc != EOK) + return rc; + + return EOK; +} + +/** @} + */ diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index 0bf10f789d..e25470e52f 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -77,6 +77,8 @@ errno_t hr_write_meta_to_vol(hr_volume_t *vol) data_blkno = vol->nblocks - data_offset; } else if (vol->level == hr_l_0) { data_blkno = vol->nblocks - (data_offset * vol->dev_no); + } else if (vol->level == hr_l_4) { + data_blkno = vol->nblocks - (data_offset * vol->dev_no) - (vol->nblocks / vol->dev_no); } else { log_msg(LOG_DEFAULT, LVL_ERROR, "level %d not implemented yet", vol->level); diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 45a48da061..84da5b0464 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -158,7 +158,7 @@ errno_t hr_check_devs(hr_volume_t *vol) if (vol->level == hr_l_1) { vol->nblocks = total_blocks / vol->dev_no; - } else if (vol->level == hr_l_0) { + } else if (vol->level == hr_l_0 || vol->level == hr_l_4) { vol->nblocks = total_blocks; } else { log_msg(LOG_DEFAULT, LVL_DEBUG, "unkown level, ok when assembling"); @@ -171,13 +171,16 @@ errno_t hr_check_devs(hr_volume_t *vol) return rc; } -errno_t hr_calc_ba(hr_volume_t *vol, size_t cnt, uint64_t *ba) +errno_t hr_check_ba_range(hr_volume_t *vol, size_t cnt, uint64_t ba) { - if (*ba + cnt > vol->data_blkno) + if (ba + cnt > vol->data_blkno) return ERANGE; + return EOK; +} +void hr_add_ba_offset(hr_volume_t *vol, uint64_t *ba) +{ *ba = *ba + vol->data_offset; - return EOK; } /** @} diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index 18aa2a49e2..b560003e02 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -44,7 +44,8 @@ extern errno_t hr_init_devs(hr_volume_t *); extern void hr_fini_devs(hr_volume_t *); extern errno_t hr_register_volume(hr_volume_t *); extern errno_t hr_check_devs(hr_volume_t *vol); -errno_t hr_calc_ba(hr_volume_t *vol, size_t cnt, uint64_t *ba); +errno_t hr_check_ba_range(hr_volume_t *vol, size_t cnt, uint64_t ba); +void hr_add_ba_offset(hr_volume_t *vol, uint64_t *ba); #endif diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index 3af5444133..2cce411251 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -71,6 +71,7 @@ extern void hr_fini_devs(hr_volume_t *); extern errno_t hr_raid0_create(hr_volume_t *); extern errno_t hr_raid1_create(hr_volume_t *); +extern errno_t hr_raid4_create(hr_volume_t *); #endif From 57c61b08d2e957e47732723ad0104ed9ab738f72 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sat, 7 Sep 2024 00:24:53 +0200 Subject: [PATCH 021/324] hr: make data start at 4K aligned offset --- uspace/srv/bd/hr/superblock.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/uspace/srv/bd/hr/superblock.h b/uspace/srv/bd/hr/superblock.h index 77657cb7c7..c46496b1f4 100644 --- a/uspace/srv/bd/hr/superblock.h +++ b/uspace/srv/bd/hr/superblock.h @@ -38,6 +38,9 @@ #include "var.h" +#define HR_META_SIZE 1 /* in blocks */ +#define HR_META_OFF 7 /* in blocks */ + #define HR_MAGIC 0x4420492041205248LLU typedef struct hr_metadata { @@ -54,9 +57,6 @@ typedef struct hr_metadata { char devname[32]; } hr_metadata_t; -#define HR_META_SIZE 1 /* in blocks */ -#define HR_META_OFF 8 /* in blocks */ - extern errno_t hr_write_meta_to_vol(hr_volume_t *); extern errno_t hr_get_vol_from_meta(hr_config_t *, hr_volume_t *); From f9440e0d0bbc3de47409752f3e00cb91a63996a2 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sat, 5 Oct 2024 11:13:35 +0200 Subject: [PATCH 022/324] hrctl: add --stop option to usage --- uspace/app/hrctl/hrctl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index 7644e5df32..91dfbd78e2 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -57,6 +57,7 @@ static const char usage_str[] = " sample file at: " HRCTL_SAMPLE_CONFIG_PATH "\n" " -A, --assemble-file=path create an array from file\n" " -s, --status display status of active arrays\n" + " -T, --stop stop an active array\n" " -c, --create=NAME create new array\n" " -a, --assemble=NAME assemble an existing array\n" " -n non-zero number of devices\n" From 34abe6c50615c0f848ae3e6cef716aa40cd6d96a Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sat, 5 Oct 2024 11:19:00 +0200 Subject: [PATCH 023/324] hrctl: inform about stopping a service that does not exit --- uspace/app/hrctl/hrctl.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index 91dfbd78e2..dfea3d162e 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -279,8 +279,12 @@ int main(int argc, char **argv) case 'T': rc = hr_stop(optarg); free(cfg); - if (rc != EOK) + if (rc != EOK) { + if (rc == ENOENT) + printf("hrctl: service named \"%s\" does not exist\n", + optarg); return 1; + } return 0; case 'l': if (cfg->level != hr_l_empty) From dbd91da773a98e6f1f92d0c5c5edcaf3a15e0b6b Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sat, 5 Oct 2024 12:23:08 +0200 Subject: [PATCH 024/324] hr: remake structures to include extent status Also rename .devs -> .extents in hr_volume_t and when printing status, display each extent status, and parity disk when array is of type RAID4. --- uspace/lib/device/include/hr.h | 7 ++++++- uspace/lib/device/src/hr.c | 16 +++++++++++++--- uspace/srv/bd/hr/hr.c | 14 ++++++++------ uspace/srv/bd/hr/raid0.c | 6 +++--- uspace/srv/bd/hr/raid1.c | 6 +++--- uspace/srv/bd/hr/raid4.c | 11 +++++------ uspace/srv/bd/hr/superblock.c | 4 ++-- uspace/srv/bd/hr/util.c | 12 ++++++------ uspace/srv/bd/hr/var.h | 2 +- 9 files changed, 47 insertions(+), 31 deletions(-) diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index 4ed60ad98d..7be7b3f870 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -63,8 +63,13 @@ typedef struct hr_config { hr_level_t level; } hr_config_t; +typedef struct hr_extent { + service_id_t svc_id; + int status; +} hr_extent_t; + typedef struct hr_vol_info { - service_id_t extents[HR_MAXDEVS]; + hr_extent_t extents[HR_MAXDEVS]; size_t extent_no; service_id_t svc_id; hr_level_t level; diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index a149597c63..d002b1f350 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -145,6 +145,7 @@ static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info) errno_t rc; size_t i; char *devname; + hr_extent_t *ext; printf("--- vol %zu ---\n", index); @@ -169,12 +170,21 @@ static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info) printf("size in blocks: %lu\n", vol_info->nblocks); printf("block size: %zu\n", vol_info->bsize); - printf("extents: [index] [devname]\n"); + if (vol_info->level == hr_l_4) + printf("extents: [P] [status] [index] [devname]\n"); + else + printf("extents: [status] [index] [devname]\n"); for (i = 0; i < vol_info->extent_no; i++) { - rc = loc_service_get_name(vol_info->extents[i], &devname); + ext = &vol_info->extents[i]; + rc = loc_service_get_name(ext->svc_id, &devname); if (rc != EOK) return rc; - printf(" %zu %s\n", i, devname); + if (i == 0 && vol_info->level == hr_l_4) + printf(" P %d %zu %s\n", ext->status, i, devname); + else if (vol_info->level == hr_l_4) + printf(" %d %zu %s\n", ext->status, i, devname); + else + printf(" %d %zu %s\n", ext->status, i, devname); } return EOK; } diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 30d7091270..b3335d0c21 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -102,7 +102,7 @@ static void hr_create_srv(ipc_call_t *icall) log_msg(LOG_DEFAULT, LVL_NOTE, "hr_create_srv()"); errno_t rc; - size_t size; + size_t i, size; hr_config_t *cfg; hr_volume_t *new_volume; ipc_call_t call; @@ -141,7 +141,8 @@ static void hr_create_srv(ipc_call_t *icall) } str_cpy(new_volume->devname, 32, cfg->devname); - memcpy(new_volume->devs, cfg->devs, sizeof(service_id_t) * HR_MAXDEVS); + for (i = 0; i < cfg->dev_no; i++) + new_volume->extents[i].svc_id = cfg->devs[i]; new_volume->level = cfg->level; new_volume->dev_no = cfg->dev_no; @@ -205,7 +206,7 @@ static void hr_assemble_srv(ipc_call_t *icall) log_msg(LOG_DEFAULT, LVL_NOTE, "hr_assemble_srv()"); errno_t rc; - size_t size; + size_t i, size; hr_config_t *cfg; hr_volume_t *new_volume; ipc_call_t call; @@ -244,7 +245,8 @@ static void hr_assemble_srv(ipc_call_t *icall) } str_cpy(new_volume->devname, 32, cfg->devname); - memcpy(new_volume->devs, cfg->devs, sizeof(service_id_t) * HR_MAXDEVS); + for (i = 0; i < cfg->dev_no; i++) + new_volume->extents[i].svc_id = cfg->devs[i]; new_volume->dev_no = cfg->dev_no; if (cfg->level != hr_l_empty) @@ -361,8 +363,8 @@ static void hr_print_status_srv(ipc_call_t *icall) goto error; list_foreach(hr_volumes, lvolumes, hr_volume_t, volume) { - memcpy(info.extents, volume->devs, - sizeof(service_id_t) * HR_MAXDEVS); + memcpy(info.extents, volume->extents, + sizeof(hr_extent_t) * HR_MAXDEVS); info.svc_id = volume->svc_id; info.extent_no = volume->dev_no; info.level = volume->level; diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index bdd8b2a7a3..53bf88119c 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -116,7 +116,7 @@ static errno_t hr_raid0_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) while (left != 0) { raid0_geometry(ba, vol, &extent, &phys_block); hr_add_ba_offset(vol, &phys_block); - rc = block_sync_cache(vol->devs[extent], phys_block, 1); + rc = block_sync_cache(vol->extents[extent].svc_id, phys_block, 1); if (rc != EOK) break; left--; @@ -148,7 +148,7 @@ static errno_t hr_raid0_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, while (left != 0) { raid0_geometry(ba, vol, &extent, &phys_block); hr_add_ba_offset(vol, &phys_block); - rc = block_read_direct(vol->devs[extent], phys_block, 1, buf); + rc = block_read_direct(vol->extents[extent].svc_id, phys_block, 1, buf); buf = buf + vol->bsize; if (rc != EOK) break; @@ -181,7 +181,7 @@ static errno_t hr_raid0_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, while (left != 0) { raid0_geometry(ba, vol, &extent, &phys_block); hr_add_ba_offset(vol, &phys_block); - rc = block_write_direct(vol->devs[extent], phys_block, 1, data); + rc = block_write_direct(vol->extents[extent].svc_id, phys_block, 1, data); data = data + vol->bsize; if (rc != EOK) break; diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 6cfd247b18..001fcde7fb 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -100,7 +100,7 @@ static errno_t hr_raid1_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) fibril_mutex_lock(&big_lock); for (i = 0; i < vol->dev_no; i++) { - rc = block_sync_cache(vol->devs[i], ba, cnt); + rc = block_sync_cache(vol->extents[i].svc_id, ba, cnt); if (rc != EOK) break; } @@ -126,7 +126,7 @@ static errno_t hr_raid1_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, fibril_mutex_lock(&big_lock); for (i = 0; i < vol->dev_no; i++) { - rc = block_read_direct(vol->devs[i], ba, cnt, buf); + rc = block_read_direct(vol->extents[i].svc_id, ba, cnt, buf); if (rc != EOK) break; } @@ -152,7 +152,7 @@ static errno_t hr_raid1_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, fibril_mutex_lock(&big_lock); for (i = 0; i < vol->dev_no; i++) { - rc = block_write_direct(vol->devs[i], ba, cnt, data); + rc = block_write_direct(vol->extents[i].svc_id, ba, cnt, data); if (rc != EOK) break; } diff --git a/uspace/srv/bd/hr/raid4.c b/uspace/srv/bd/hr/raid4.c index 2ec825c0fa..518c6dde3e 100644 --- a/uspace/srv/bd/hr/raid4.c +++ b/uspace/srv/bd/hr/raid4.c @@ -103,14 +103,14 @@ static errno_t write_parity(hr_volume_t *vol, uint64_t extent, uint64_t block, if (i == extent) { xor(xorbuf, data, vol->bsize); } else { - rc = block_read_direct(vol->devs[i], block, 1, buf); + rc = block_read_direct(vol->extents[i].svc_id, block, 1, buf); if (rc != EOK) goto end; xor(xorbuf, buf, vol->bsize); } } - rc = block_write_direct(vol->devs[0], block, 1, xorbuf); + rc = block_write_direct(vol->extents[0].svc_id, block, 1, xorbuf); end: free(xorbuf); @@ -161,7 +161,7 @@ static errno_t hr_raid4_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) while (left != 0) { raid4_geometry(ba, vol, &extent, &phys_block); hr_add_ba_offset(vol, &phys_block); - rc = block_sync_cache(vol->devs[extent], phys_block, 1); + rc = block_sync_cache(vol->extents[extent].svc_id, phys_block, 1); if (rc != EOK) break; left--; @@ -193,7 +193,7 @@ static errno_t hr_raid4_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, while (left != 0) { raid4_geometry(ba, vol, &extent, &phys_block); hr_add_ba_offset(vol, &phys_block); - rc = block_read_direct(vol->devs[extent], phys_block, 1, buf); + rc = block_read_direct(vol->extents[extent].svc_id, phys_block, 1, buf); buf = buf + vol->bsize; if (rc != EOK) break; @@ -205,7 +205,6 @@ static errno_t hr_raid4_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, return rc; } - static errno_t hr_raid4_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, const void *data, size_t size) { @@ -227,7 +226,7 @@ static errno_t hr_raid4_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, while (left != 0) { raid4_geometry(ba, vol, &extent, &phys_block); hr_add_ba_offset(vol, &phys_block); - rc = block_write_direct(vol->devs[extent], phys_block, 1, data); + rc = block_write_direct(vol->extents[extent].svc_id, phys_block, 1, data); if (rc != EOK) break; rc = write_parity(vol, extent, phys_block, data); diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index e25470e52f..8a45cbd436 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -102,7 +102,7 @@ errno_t hr_write_meta_to_vol(hr_volume_t *vol) str_cpy(metadata->devname, 32, vol->devname); - rc = block_write_direct(vol->devs[i], HR_META_OFF, HR_META_SIZE, + rc = block_write_direct(vol->extents[i].svc_id, HR_META_OFF, HR_META_SIZE, metadata); if (rc != EOK) goto error; @@ -133,7 +133,7 @@ errno_t hr_get_vol_from_meta(hr_config_t *cfg, hr_volume_t *new_volume) if (rc != EOK) goto end; - /* TODO: sort new_volume->devs according to metadata extent index */ + /* TODO: sort new_volume->extents according to metadata extent index */ if (uint64_t_le2host(metadata->magic) != HR_MAGIC) { printf("invalid magic\n"); diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 84da5b0464..54b8a3b51d 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -55,13 +55,13 @@ errno_t hr_init_devs(hr_volume_t *vol) size_t i; for (i = 0; i < vol->dev_no; i++) { - rc = block_init(vol->devs[i]); + rc = block_init(vol->extents[i].svc_id); log_msg(LOG_DEFAULT, LVL_DEBUG, - "hr_init_devs(): initing (%" PRIun ")", vol->devs[i]); + "hr_init_devs(): initing (%" PRIun ")", vol->extents[i].svc_id); if (rc != EOK) { log_msg(LOG_DEFAULT, LVL_ERROR, "hr_init_devs(): initing (%" PRIun ") failed, aborting", - vol->devs[i]); + vol->extents[i].svc_id); break; } } @@ -76,7 +76,7 @@ void hr_fini_devs(hr_volume_t *vol) size_t i; for (i = 0; i < vol->dev_no; i++) - block_fini(vol->devs[i]); + block_fini(vol->extents[i].svc_id); } errno_t hr_register_volume(hr_volume_t *new_volume) @@ -131,7 +131,7 @@ errno_t hr_check_devs(hr_volume_t *vol) uint64_t total_blocks = 0; for (i = 0; i < vol->dev_no; i++) { - rc = block_get_nblocks(vol->devs[i], &nblocks); + rc = block_get_nblocks(vol->extents[i].svc_id, &nblocks); if (rc != EOK) goto error; if (i != 0 && nblocks != last_nblocks) { @@ -145,7 +145,7 @@ errno_t hr_check_devs(hr_volume_t *vol) } for (i = 0; i < vol->dev_no; i++) { - rc = block_get_bsize(vol->devs[i], &bsize); + rc = block_get_bsize(vol->extents[i].svc_id, &bsize); if (rc != EOK) goto error; if (i != 0 && bsize != last_bsize) { diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index 2cce411251..93c6bd1e08 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -55,7 +55,7 @@ typedef struct hr_volume { bd_srvs_t hr_bds; link_t lvolumes; char devname[32]; - service_id_t devs[HR_MAXDEVS]; + hr_extent_t extents[HR_MAXDEVS]; uint64_t nblocks; uint64_t data_blkno; uint32_t data_offset; From 6b8e89b02035d2148fde496fb715b80f3df10686 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sat, 5 Oct 2024 14:39:13 +0200 Subject: [PATCH 025/324] hr: init fuction for each RAID level Compute total blocks, data blocks and set block size, data offset, strip size there. --- uspace/srv/bd/hr/hr.c | 17 ++++++++------- uspace/srv/bd/hr/raid0.c | 22 +++++++++++++++++++ uspace/srv/bd/hr/raid1.c | 22 +++++++++++++++++++ uspace/srv/bd/hr/raid4.c | 23 ++++++++++++++++++++ uspace/srv/bd/hr/superblock.c | 41 ++++++++++++++--------------------- uspace/srv/bd/hr/superblock.h | 1 + uspace/srv/bd/hr/util.c | 17 +++++---------- uspace/srv/bd/hr/util.h | 6 ++--- uspace/srv/bd/hr/var.h | 7 +++++- 9 files changed, 107 insertions(+), 49 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index b3335d0c21..5b8a36106f 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -153,22 +153,18 @@ static void hr_create_srv(ipc_call_t *icall) return; } - rc = hr_check_devs(new_volume); - if (rc != EOK) - goto error; - switch (new_volume->level) { case hr_l_1: new_volume->hr_ops.create = hr_raid1_create; - new_volume->strip_size = 0; + new_volume->hr_ops.init = hr_raid1_init; break; case hr_l_0: new_volume->hr_ops.create = hr_raid0_create; - new_volume->strip_size = HR_STRIP_SIZE; + new_volume->hr_ops.init = hr_raid0_init; break; case hr_l_4: new_volume->hr_ops.create = hr_raid4_create; - new_volume->strip_size = HR_STRIP_SIZE; + new_volume->hr_ops.init = hr_raid4_init; break; default: log_msg(LOG_DEFAULT, LVL_ERROR, @@ -177,6 +173,10 @@ static void hr_create_srv(ipc_call_t *icall) goto error; } + new_volume->hr_ops.init(new_volume); + if (rc != EOK) + goto error; + rc = hr_write_meta_to_vol(new_volume); if (rc != EOK) goto error; @@ -262,7 +262,8 @@ static void hr_assemble_srv(ipc_call_t *icall) return; } - rc = hr_check_devs(new_volume); + /* just bsize needed for reading metadata later */ + rc = hr_check_devs(new_volume, NULL, &new_volume->bsize); if (rc != EOK) goto error; diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index 53bf88119c..2b8b27f8e8 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -47,6 +47,7 @@ #include #include +#include "superblock.h" #include "util.h" #include "var.h" @@ -232,5 +233,26 @@ errno_t hr_raid0_create(hr_volume_t *new_volume) return EOK; } +errno_t hr_raid0_init(hr_volume_t *vol) +{ + errno_t rc; + size_t bsize; + uint64_t total_blkno; + + assert(vol->level == hr_l_0); + + rc = hr_check_devs(vol, &total_blkno, &bsize); + if (rc != EOK) + return rc; + + vol->nblocks = total_blkno; + vol->bsize = bsize; + vol->data_offset = HR_DATA_OFF; + vol->data_blkno = vol->nblocks - (vol->data_offset * vol->dev_no); + vol->strip_size = HR_STRIP_SIZE; + + return EOK; +} + /** @} */ diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 001fcde7fb..33cd6df21f 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -46,6 +46,7 @@ #include #include +#include "superblock.h" #include "util.h" #include "var.h" @@ -200,5 +201,26 @@ errno_t hr_raid1_create(hr_volume_t *new_volume) return EOK; } +errno_t hr_raid1_init(hr_volume_t *vol) +{ + errno_t rc; + size_t bsize; + uint64_t total_blkno; + + assert(vol->level == hr_l_1); + + rc = hr_check_devs(vol, &total_blkno, &bsize); + if (rc != EOK) + return rc; + + vol->nblocks = total_blkno / vol->dev_no; + vol->bsize = bsize; + vol->data_offset = HR_DATA_OFF; + vol->data_blkno = vol->nblocks - vol->data_offset; + vol->strip_size = 0; + + return EOK; +} + /** @} */ diff --git a/uspace/srv/bd/hr/raid4.c b/uspace/srv/bd/hr/raid4.c index 518c6dde3e..b9a6dfe9e0 100644 --- a/uspace/srv/bd/hr/raid4.c +++ b/uspace/srv/bd/hr/raid4.c @@ -47,6 +47,7 @@ #include #include +#include "superblock.h" #include "util.h" #include "var.h" @@ -280,5 +281,27 @@ errno_t hr_raid4_create(hr_volume_t *new_volume) return EOK; } +errno_t hr_raid4_init(hr_volume_t *vol) +{ + errno_t rc; + size_t bsize; + uint64_t total_blkno; + + assert(vol->level == hr_l_4); + + rc = hr_check_devs(vol, &total_blkno, &bsize); + if (rc != EOK) + return rc; + + vol->nblocks = total_blkno; + vol->bsize = bsize; + vol->data_offset = HR_DATA_OFF; + vol->data_blkno = vol->nblocks - (vol->data_offset * vol->dev_no) - + (vol->nblocks / vol->dev_no); + vol->strip_size = HR_STRIP_SIZE; + + return EOK; +} + /** @} */ diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index 8a45cbd436..199c125db2 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -56,8 +56,8 @@ errno_t hr_write_meta_to_vol(hr_volume_t *vol) log_msg(LOG_DEFAULT, LVL_NOTE, "hr_write_meta_to_vol()"); errno_t rc; - size_t i, data_offset; - uint64_t data_blkno; + size_t i; + size_t meta_blkno; /* blocks needed to write metadata */ hr_metadata_t *metadata; uuid_t uuid; @@ -65,32 +65,28 @@ errno_t hr_write_meta_to_vol(hr_volume_t *vol) if (metadata == NULL) return ENOMEM; - if (vol->nblocks <= HR_META_OFF + HR_META_SIZE) { + meta_blkno = (HR_META_OFF + HR_META_SIZE); + if (vol->level != hr_l_1) + meta_blkno *= vol->dev_no; + + if (vol->nblocks < meta_blkno) { log_msg(LOG_DEFAULT, LVL_ERROR, - "not enough blocks"); + "not enough blocks to write metadata"); rc = EINVAL; goto error; - } - - data_offset = HR_META_OFF + HR_META_SIZE; - if (vol->level == hr_l_1) { - data_blkno = vol->nblocks - data_offset; - } else if (vol->level == hr_l_0) { - data_blkno = vol->nblocks - (data_offset * vol->dev_no); - } else if (vol->level == hr_l_4) { - data_blkno = vol->nblocks - (data_offset * vol->dev_no) - (vol->nblocks / vol->dev_no); - } else { + } else if (vol->nblocks == meta_blkno) { log_msg(LOG_DEFAULT, LVL_ERROR, - "level %d not implemented yet", vol->level); - return EINVAL; + "there would be zero data blocks after writing metadata, aborting"); + rc = EINVAL; + goto error; } metadata->magic = host2uint64_t_le(HR_MAGIC); metadata->extent_no = host2uint32_t_le(vol->dev_no); metadata->level = host2uint32_t_le(vol->level); metadata->nblocks = host2uint64_t_le(vol->nblocks); - metadata->data_blkno = host2uint64_t_le(data_blkno); - metadata->data_offset = host2uint32_t_le(data_offset); + metadata->data_blkno = host2uint64_t_le(vol->data_blkno); + metadata->data_offset = host2uint32_t_le(vol->data_offset); metadata->strip_size = host2uint32_t_le(vol->strip_size); for (i = 0; i < vol->dev_no; i++) { metadata->index = host2uint32_t_le(i); @@ -102,16 +98,11 @@ errno_t hr_write_meta_to_vol(hr_volume_t *vol) str_cpy(metadata->devname, 32, vol->devname); - rc = block_write_direct(vol->extents[i].svc_id, HR_META_OFF, HR_META_SIZE, - metadata); + rc = block_write_direct(vol->extents[i].svc_id, HR_META_OFF, + HR_META_SIZE, metadata); if (rc != EOK) goto error; } - - /* fill in new members */ - vol->data_offset = data_offset; - vol->data_blkno = data_blkno; - error: free(metadata); return rc; diff --git a/uspace/srv/bd/hr/superblock.h b/uspace/srv/bd/hr/superblock.h index c46496b1f4..66250bd49b 100644 --- a/uspace/srv/bd/hr/superblock.h +++ b/uspace/srv/bd/hr/superblock.h @@ -40,6 +40,7 @@ #define HR_META_SIZE 1 /* in blocks */ #define HR_META_OFF 7 /* in blocks */ +#define HR_DATA_OFF (HR_META_SIZE + HR_META_OFF) #define HR_MAGIC 0x4420492041205248LLU diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 54b8a3b51d..4d0649679b 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -121,7 +121,7 @@ errno_t hr_register_volume(hr_volume_t *new_volume) return rc; } -errno_t hr_check_devs(hr_volume_t *vol) +errno_t hr_check_devs(hr_volume_t *vol, uint64_t *rblkno, size_t *rbsize) { log_msg(LOG_DEFAULT, LVL_NOTE, "hr_check_devs()"); @@ -156,17 +156,10 @@ errno_t hr_check_devs(hr_volume_t *vol) last_bsize = bsize; } - if (vol->level == hr_l_1) { - vol->nblocks = total_blocks / vol->dev_no; - } else if (vol->level == hr_l_0 || vol->level == hr_l_4) { - vol->nblocks = total_blocks; - } else { - log_msg(LOG_DEFAULT, LVL_DEBUG, "unkown level, ok when assembling"); - vol->nblocks = 0; - } - - vol->bsize = bsize; - + if (rblkno != NULL) + *rblkno = total_blocks; + if (rbsize != NULL) + *rbsize = bsize; error: return rc; } diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index b560003e02..b2c68940e9 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -43,9 +43,9 @@ extern errno_t hr_init_devs(hr_volume_t *); extern void hr_fini_devs(hr_volume_t *); extern errno_t hr_register_volume(hr_volume_t *); -extern errno_t hr_check_devs(hr_volume_t *vol); -errno_t hr_check_ba_range(hr_volume_t *vol, size_t cnt, uint64_t ba); -void hr_add_ba_offset(hr_volume_t *vol, uint64_t *ba); +errno_t hr_check_devs(hr_volume_t *, uint64_t *, size_t *); +errno_t hr_check_ba_range(hr_volume_t *, size_t, uint64_t); +void hr_add_ba_offset(hr_volume_t *, uint64_t *); #endif diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index 93c6bd1e08..35aae3bdc2 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -48,6 +48,7 @@ typedef struct hr_volume hr_volume_t; typedef struct hr_ops { errno_t (*create)(hr_volume_t *); + errno_t (*init)(hr_volume_t *); } hr_ops_t; typedef struct hr_volume { @@ -58,7 +59,7 @@ typedef struct hr_volume { hr_extent_t extents[HR_MAXDEVS]; uint64_t nblocks; uint64_t data_blkno; - uint32_t data_offset; + uint32_t data_offset; /* in blocks */ uint32_t strip_size; service_id_t svc_id; size_t bsize; @@ -73,6 +74,10 @@ extern errno_t hr_raid0_create(hr_volume_t *); extern errno_t hr_raid1_create(hr_volume_t *); extern errno_t hr_raid4_create(hr_volume_t *); +extern errno_t hr_raid0_init(hr_volume_t *); +extern errno_t hr_raid1_init(hr_volume_t *); +extern errno_t hr_raid4_init(hr_volume_t *); + #endif /** @} From dceb6e71aff0dbfd858c56da3581e0d1a46bfc7a Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sat, 5 Oct 2024 23:51:04 +0200 Subject: [PATCH 026/324] hr: add initial RAID 5 with parity starting on extent 0 and data restart --- uspace/srv/bd/hr/hr.c | 7 + uspace/srv/bd/hr/meson.build | 2 +- uspace/srv/bd/hr/raid5.c | 319 +++++++++++++++++++++++++++++++++++ uspace/srv/bd/hr/var.h | 2 + 4 files changed, 329 insertions(+), 1 deletion(-) create mode 100644 uspace/srv/bd/hr/raid5.c diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 5b8a36106f..24b82c0bbc 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -166,6 +166,10 @@ static void hr_create_srv(ipc_call_t *icall) new_volume->hr_ops.create = hr_raid4_create; new_volume->hr_ops.init = hr_raid4_init; break; + case hr_l_5: + new_volume->hr_ops.create = hr_raid5_create; + new_volume->hr_ops.init = hr_raid5_init; + break; default: log_msg(LOG_DEFAULT, LVL_ERROR, "level %d not implemented yet", new_volume->level); @@ -281,6 +285,9 @@ static void hr_assemble_srv(ipc_call_t *icall) case hr_l_4: new_volume->hr_ops.create = hr_raid4_create; break; + case hr_l_5: + new_volume->hr_ops.create = hr_raid5_create; + break; default: log_msg(LOG_DEFAULT, LVL_ERROR, "level %d not implemented yet", new_volume->level); diff --git a/uspace/srv/bd/hr/meson.build b/uspace/srv/bd/hr/meson.build index 250f9c853a..2d61303f70 100644 --- a/uspace/srv/bd/hr/meson.build +++ b/uspace/srv/bd/hr/meson.build @@ -27,4 +27,4 @@ # deps = [ 'block', 'device' ] -src = files('hr.c', 'raid0.c', 'raid1.c', 'raid4.c', 'superblock.c', 'util.c') +src = files('hr.c', 'raid0.c', 'raid1.c', 'raid4.c', 'raid5.c', 'superblock.c', 'util.c') diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c new file mode 100644 index 0000000000..7db56b7822 --- /dev/null +++ b/uspace/srv/bd/hr/raid5.c @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2024 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 +#include +#include +#include +#include + +#include "superblock.h" +#include "util.h" +#include "var.h" + +extern fibril_mutex_t big_lock; +extern loc_srv_t *hr_srv; + +static errno_t hr_raid5_bd_open(bd_srvs_t *, bd_srv_t *); +static errno_t hr_raid5_bd_close(bd_srv_t *); +static errno_t hr_raid5_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, + size_t); +static errno_t hr_raid5_bd_sync_cache(bd_srv_t *, aoff64_t, size_t); +static errno_t hr_raid5_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, + const void *, size_t); +static errno_t hr_raid5_bd_get_block_size(bd_srv_t *, size_t *); +static errno_t hr_raid5_bd_get_num_blocks(bd_srv_t *, aoff64_t *); + +static bd_ops_t hr_raid5_bd_ops = { + .open = hr_raid5_bd_open, + .close = hr_raid5_bd_close, + .sync_cache = hr_raid5_bd_sync_cache, + .read_blocks = hr_raid5_bd_read_blocks, + .write_blocks = hr_raid5_bd_write_blocks, + .get_block_size = hr_raid5_bd_get_block_size, + .get_num_blocks = hr_raid5_bd_get_num_blocks +}; + +static void xor(void *dst, const void *src, size_t size) +{ + size_t i; + uint64_t *d = dst; + const uint64_t *s = src; + + for (i = 0; i < size / sizeof(uint64_t); ++i) + *d++ ^= *s++; +} + +static errno_t write_parity(hr_volume_t *vol, uint64_t p_extent, + uint64_t extent, uint64_t block, const void *data) +{ + errno_t rc; + size_t i; + void *xorbuf; + void *buf; + + xorbuf = calloc(1, vol->bsize); + if (xorbuf == NULL) + return ENOMEM; + + buf = malloc(vol->bsize); + if (buf == NULL) + return ENOMEM; + + for (i = 0; i < vol->dev_no; i++) { + if (i == p_extent) + continue; + + if (i == extent) { + xor(xorbuf, data, vol->bsize); + } else { + rc = block_read_direct(vol->extents[i].svc_id, block, 1, buf); + if (rc != EOK) + goto end; + xor(xorbuf, buf, vol->bsize); + } + } + + rc = block_write_direct(vol->extents[p_extent].svc_id, block, 1, xorbuf); + +end: + free(xorbuf); + free(buf); + return EOK; +} + +static void raid5_geometry(uint64_t x, hr_volume_t *vol, size_t *extent, + uint64_t *phys_block, uint64_t *p_extent) +{ + uint64_t N = vol->dev_no; /* extents */ + uint64_t L = vol->strip_size / vol->bsize; /* size of strip in blocks */ + + uint64_t p = ((x / L) / (N - 1)) % N; + + uint64_t i; /* extent */ + if (((x / L) % (N - 1)) < p) + i = (x / L) % (N - 1); + else + i = ((x / L) % (N - 1)) + 1; + + uint64_t j = (x / L) / (N - 1); /* stripe */ + uint64_t k = x % L; /* strip offset */ + + *extent = i; + *phys_block = j * L + k; + if (p_extent != NULL) + *p_extent = p; +} + +static errno_t hr_raid5_bd_open(bd_srvs_t *bds, bd_srv_t *bd) +{ + log_msg(LOG_DEFAULT, LVL_NOTE, "hr_bd_open()"); + return EOK; +} + +static errno_t hr_raid5_bd_close(bd_srv_t *bd) +{ + log_msg(LOG_DEFAULT, LVL_NOTE, "hr_bd_close()"); + return EOK; +} + +static errno_t hr_raid5_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) +{ + hr_volume_t *vol = bd->srvs->sarg; + errno_t rc; + uint64_t phys_block; + size_t extent; + + rc = hr_check_ba_range(vol, cnt, ba); + if (rc != EOK) + return rc; + + fibril_mutex_lock(&big_lock); + + size_t left = cnt; + while (left != 0) { + raid5_geometry(ba, vol, &extent, &phys_block, NULL); + hr_add_ba_offset(vol, &phys_block); + rc = block_sync_cache(vol->extents[extent].svc_id, phys_block, 1); + if (rc != EOK) + break; + left--; + ba++; + } + + fibril_mutex_unlock(&big_lock); + return rc; +} + +static errno_t hr_raid5_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, + void *buf, size_t size) +{ + hr_volume_t *vol = bd->srvs->sarg; + errno_t rc; + uint64_t phys_block; + size_t extent; + + if (size < cnt * vol->bsize) + return EINVAL; + + rc = hr_check_ba_range(vol, cnt, ba); + if (rc != EOK) + return rc; + + fibril_mutex_lock(&big_lock); + + size_t left = cnt; + while (left != 0) { + raid5_geometry(ba, vol, &extent, &phys_block, NULL); + hr_add_ba_offset(vol, &phys_block); + rc = block_read_direct(vol->extents[extent].svc_id, phys_block, 1, buf); + buf = buf + vol->bsize; + if (rc != EOK) + break; + left--; + ba++; + } + + fibril_mutex_unlock(&big_lock); + return rc; +} + +static errno_t hr_raid5_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, + const void *data, size_t size) +{ + hr_volume_t *vol = bd->srvs->sarg; + errno_t rc; + uint64_t phys_block, p_extent; + size_t extent; + + if (size < cnt * vol->bsize) + return EINVAL; + + rc = hr_check_ba_range(vol, cnt, ba); + if (rc != EOK) + return rc; + + fibril_mutex_lock(&big_lock); + + size_t left = cnt; + while (left != 0) { + raid5_geometry(ba, vol, &extent, &phys_block, &p_extent); + hr_add_ba_offset(vol, &phys_block); + rc = block_write_direct(vol->extents[extent].svc_id, phys_block, 1, data); + if (rc != EOK) + break; + rc = write_parity(vol, p_extent, extent, phys_block, data); + if (rc != EOK) + break; + data = data + vol->bsize; + left--; + ba++; + } + + fibril_mutex_unlock(&big_lock); + return rc; +} + +static errno_t hr_raid5_bd_get_block_size(bd_srv_t *bd, size_t *rsize) +{ + hr_volume_t *vol = bd->srvs->sarg; + + *rsize = vol->bsize; + return EOK; +} + +static errno_t hr_raid5_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb) +{ + hr_volume_t *vol = bd->srvs->sarg; + + *rnb = vol->data_blkno; + return EOK; +} + +errno_t hr_raid5_create(hr_volume_t *new_volume) +{ + errno_t rc; + + assert(new_volume->level == hr_l_5); + + if (new_volume->dev_no < 3) { + log_msg(LOG_DEFAULT, LVL_ERROR, + "RAID 5 array needs at least 3 devices"); + return EINVAL; + } + + bd_srvs_init(&new_volume->hr_bds); + new_volume->hr_bds.ops = &hr_raid5_bd_ops; + new_volume->hr_bds.sarg = new_volume; + + rc = hr_register_volume(new_volume); + if (rc != EOK) + return rc; + + return EOK; +} + +errno_t hr_raid5_init(hr_volume_t *vol) +{ + errno_t rc; + size_t bsize; + uint64_t total_blkno; + + assert(vol->level == hr_l_5); + + rc = hr_check_devs(vol, &total_blkno, &bsize); + if (rc != EOK) + return rc; + + vol->nblocks = total_blkno; + vol->bsize = bsize; + vol->data_offset = HR_DATA_OFF; + vol->data_blkno = vol->nblocks - (vol->data_offset * vol->dev_no) - + (vol->nblocks / vol->dev_no); + vol->strip_size = HR_STRIP_SIZE; + + return EOK; +} + +/** @} + */ diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index 35aae3bdc2..e4d3baa44b 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -73,10 +73,12 @@ extern void hr_fini_devs(hr_volume_t *); extern errno_t hr_raid0_create(hr_volume_t *); extern errno_t hr_raid1_create(hr_volume_t *); extern errno_t hr_raid4_create(hr_volume_t *); +extern errno_t hr_raid5_create(hr_volume_t *); extern errno_t hr_raid0_init(hr_volume_t *); extern errno_t hr_raid1_init(hr_volume_t *); extern errno_t hr_raid4_init(hr_volume_t *); +extern errno_t hr_raid5_init(hr_volume_t *); #endif From 2b8901bea57b835487c649506b7d6acc099dd9b3 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sat, 5 Oct 2024 23:59:05 +0200 Subject: [PATCH 027/324] hrctl: add RAID 4 to usage message --- uspace/app/hrctl/hrctl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index dfea3d162e..9153c5a1c2 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -62,9 +62,10 @@ static const char usage_str[] = " -a, --assemble=NAME assemble an existing array\n" " -n non-zero number of devices\n" " -l, --level=LEVEL set the RAID level,\n" - " valid values: 0, 1, 5, linear\n" + " valid values: 0, 1, 4, 5, linear\n" " -0 striping\n" " -1 mirroring\n" + " -4 parity on one extent\n" " -5 distributed parity\n" " -L linear concatenation\n" "\n" From c99737458ece83464a11711065db030e166971c0 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Thu, 10 Oct 2024 15:31:42 +0200 Subject: [PATCH 028/324] hr: merge assemble and create functions --- uspace/app/hrctl/hrctl.c | 4 +- uspace/lib/device/include/hr.h | 3 +- uspace/lib/device/src/hr.c | 31 +------ uspace/srv/bd/hr/hr.c | 157 ++++++++------------------------- 4 files changed, 42 insertions(+), 153 deletions(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index 9153c5a1c2..65a85b3ec9 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -358,10 +358,10 @@ int main(int argc, char **argv) } if (create) { - rc = hr_create(hr, cfg); + rc = hr_create(hr, cfg, false); printf("hrctl: hr_create() rc: %s\n", str_error(rc)); } else if (assemble) { - rc = hr_assemble(hr, cfg); + rc = hr_create(hr, cfg, true); printf("hrctl: hr_assemble() rc: %s\n", str_error(rc)); } diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index 7be7b3f870..f4d8624bb9 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -81,8 +81,7 @@ typedef struct hr_vol_info { extern errno_t hr_sess_init(hr_t **); extern void hr_sess_destroy(hr_t *); -extern errno_t hr_create(hr_t *, hr_config_t *); -extern errno_t hr_assemble(hr_t *, hr_config_t *); +extern errno_t hr_create(hr_t *, hr_config_t *, bool); extern errno_t hr_stop(const char *); extern errno_t hr_print_status(void); diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index d002b1f350..aae7c82fb3 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -86,7 +86,7 @@ void hr_sess_destroy(hr_t *hr) free(hr); } -errno_t hr_create(hr_t *hr, hr_config_t *hr_config) +errno_t hr_create(hr_t *hr, hr_config_t *hr_config, bool assemble) { errno_t rc, retval; async_exch_t *exch; @@ -96,34 +96,7 @@ errno_t hr_create(hr_t *hr, hr_config_t *hr_config) if (exch == NULL) return EINVAL; - req = async_send_0(exch, HR_CREATE, NULL); - - rc = async_data_write_start(exch, hr_config, sizeof(hr_config_t)); - if (rc != EOK) { - async_exchange_end(exch); - async_forget(req); - return rc; - } - - async_exchange_end(exch); - async_wait_for(req, &retval); - if (retval != EOK) - return retval; - - return EOK; -} - -errno_t hr_assemble(hr_t *hr, hr_config_t *hr_config) -{ - errno_t rc, retval; - async_exch_t *exch; - aid_t req; - - exch = async_exchange_begin(hr->sess); - if (exch == NULL) - return EINVAL; - - req = async_send_0(exch, HR_ASSEMBLE, NULL); + req = async_send_0(exch, assemble ? HR_ASSEMBLE : HR_CREATE, NULL); rc = async_data_write_start(exch, hr_config, sizeof(hr_config_t)); if (rc != EOK) { diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 24b82c0bbc..7cf54051b8 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -97,7 +97,7 @@ static errno_t hr_remove_volume(service_id_t svc_id) return ENOENT; } -static void hr_create_srv(ipc_call_t *icall) +static void hr_create_srv(ipc_call_t *icall, bool assemble) { log_msg(LOG_DEFAULT, LVL_NOTE, "hr_create_srv()"); @@ -146,6 +146,13 @@ static void hr_create_srv(ipc_call_t *icall) new_volume->level = cfg->level; new_volume->dev_no = cfg->dev_no; + if (assemble) { + if (cfg->level != hr_l_empty) + log_msg(LOG_DEFAULT, LVL_WARN, + "level manually set when assembling, ingoring"); + new_volume->level = hr_l_empty; + } + rc = hr_init_devs(new_volume); if (rc != EOK) { free(cfg); @@ -153,6 +160,17 @@ static void hr_create_srv(ipc_call_t *icall) return; } + if (assemble) { + /* just bsize needed for reading metadata later */ + rc = hr_check_devs(new_volume, NULL, &new_volume->bsize); + if (rc != EOK) + goto error; + + rc = hr_get_vol_from_meta(cfg, new_volume); + if (rc != EOK) + goto error; + } + switch (new_volume->level) { case hr_l_1: new_volume->hr_ops.create = hr_raid1_create; @@ -177,122 +195,14 @@ static void hr_create_srv(ipc_call_t *icall) goto error; } - new_volume->hr_ops.init(new_volume); - if (rc != EOK) - goto error; - - rc = hr_write_meta_to_vol(new_volume); - if (rc != EOK) - goto error; - - rc = new_volume->hr_ops.create(new_volume); - if (rc != EOK) - goto error; - - fibril_mutex_lock(&hr_volumes_lock); - list_append(&new_volume->lvolumes, &hr_volumes); - fibril_mutex_unlock(&hr_volumes_lock); - - log_msg(LOG_DEFAULT, LVL_NOTE, "created volume \"%s\" (%" PRIun ")", - new_volume->devname, new_volume->svc_id); - - free(cfg); - async_answer_0(icall, rc); - return; -error: - free(cfg); - hr_fini_devs(new_volume); - async_answer_0(icall, rc); -} - -static void hr_assemble_srv(ipc_call_t *icall) -{ - log_msg(LOG_DEFAULT, LVL_NOTE, "hr_assemble_srv()"); - - errno_t rc; - size_t i, size; - hr_config_t *cfg; - hr_volume_t *new_volume; - ipc_call_t call; - - if (!async_data_write_receive(&call, &size)) { - async_answer_0(&call, EREFUSED); - async_answer_0(icall, EREFUSED); - return; - } - - if (size != sizeof(hr_config_t)) { - async_answer_0(&call, EINVAL); - async_answer_0(icall, EINVAL); - return; - } - - cfg = calloc(1, sizeof(hr_config_t)); - if (cfg == NULL) { - async_answer_0(&call, ENOMEM); - async_answer_0(icall, ENOMEM); - return; - } - - rc = async_data_write_finalize(&call, cfg, size); - if (rc != EOK) { - async_answer_0(&call, rc); - async_answer_0(icall, rc); - return; - } - - new_volume = calloc(1, sizeof(hr_volume_t)); - if (new_volume == NULL) { - free(cfg); - async_answer_0(icall, ENOMEM); - return; - } - - str_cpy(new_volume->devname, 32, cfg->devname); - for (i = 0; i < cfg->dev_no; i++) - new_volume->extents[i].svc_id = cfg->devs[i]; - new_volume->dev_no = cfg->dev_no; - - if (cfg->level != hr_l_empty) - log_msg(LOG_DEFAULT, LVL_WARN, - "level manually set when assembling, ingoring"); - - new_volume->level = hr_l_empty; - - rc = hr_init_devs(new_volume); - if (rc != EOK) { - free(cfg); - async_answer_0(icall, rc); - return; - } - - /* just bsize needed for reading metadata later */ - rc = hr_check_devs(new_volume, NULL, &new_volume->bsize); - if (rc != EOK) - goto error; - - rc = hr_get_vol_from_meta(cfg, new_volume); - if (rc != EOK) - goto error; + if (!assemble) { + new_volume->hr_ops.init(new_volume); + if (rc != EOK) + goto error; - switch (new_volume->level) { - case hr_l_1: - new_volume->hr_ops.create = hr_raid1_create; - break; - case hr_l_0: - new_volume->hr_ops.create = hr_raid0_create; - break; - case hr_l_4: - new_volume->hr_ops.create = hr_raid4_create; - break; - case hr_l_5: - new_volume->hr_ops.create = hr_raid5_create; - break; - default: - log_msg(LOG_DEFAULT, LVL_ERROR, - "level %d not implemented yet", new_volume->level); - rc = EINVAL; - goto error; + rc = hr_write_meta_to_vol(new_volume); + if (rc != EOK) + goto error; } rc = new_volume->hr_ops.create(new_volume); @@ -303,8 +213,15 @@ static void hr_assemble_srv(ipc_call_t *icall) list_append(&new_volume->lvolumes, &hr_volumes); fibril_mutex_unlock(&hr_volumes_lock); - log_msg(LOG_DEFAULT, LVL_NOTE, "assembled volume \"%s\" (%" PRIun ")", - new_volume->devname, new_volume->svc_id); + if (assemble) { + log_msg(LOG_DEFAULT, LVL_NOTE, + "assembled volume \"%s\" (%" PRIun ")", + new_volume->devname, new_volume->svc_id); + } else { + log_msg(LOG_DEFAULT, LVL_NOTE, + "created volume \"%s\" (%" PRIun ")", + new_volume->devname, new_volume->svc_id); + } free(cfg); async_answer_0(icall, rc); @@ -423,10 +340,10 @@ static void hr_ctl_conn(ipc_call_t *icall, void *arg) switch (method) { case HR_CREATE: - hr_create_srv(&call); + hr_create_srv(&call, false); break; case HR_ASSEMBLE: - hr_assemble_srv(&call); + hr_create_srv(&call, true); break; case HR_STOP: hr_stop_srv(&call); From 4b759dcc9ca070521b8c619dceb603aa7f1bcbd3 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Thu, 10 Oct 2024 23:53:29 +0200 Subject: [PATCH 029/324] hr: sleep to get new random generator for UUID --- uspace/srv/bd/hr/superblock.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index 199c125db2..c0099c5a2c 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -102,6 +102,9 @@ errno_t hr_write_meta_to_vol(hr_volume_t *vol) HR_META_SIZE, metadata); if (rc != EOK) goto error; + + /* rndgen */ + fibril_usleep(1000); } error: free(metadata); From 68c966e1cb7a84eed42455def54ec97cf5279e73 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 11 Oct 2024 19:37:03 +0200 Subject: [PATCH 030/324] hr: use HR_DEVNAME_LEN and HR_UUID_LEN defines --- uspace/lib/device/include/hr.h | 4 +++- uspace/srv/bd/hr/hr.c | 2 +- uspace/srv/bd/hr/superblock.c | 2 +- uspace/srv/bd/hr/superblock.h | 5 +++-- uspace/srv/bd/hr/var.h | 2 +- 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index f4d8624bb9..d346fd29a3 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -43,6 +43,8 @@ /* for now */ #define HR_MAXDEVS 4 +#define HR_DEVNAME_LEN 32 + typedef struct hr { async_sess_t *sess; } hr_t; @@ -57,7 +59,7 @@ typedef enum hr_level { } hr_level_t; typedef struct hr_config { - char devname[32]; + char devname[HR_DEVNAME_LEN]; service_id_t devs[HR_MAXDEVS]; size_t dev_no; hr_level_t level; diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 7cf54051b8..a9b7a5d38f 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -140,7 +140,7 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) return; } - str_cpy(new_volume->devname, 32, cfg->devname); + str_cpy(new_volume->devname, HR_DEVNAME_LEN, cfg->devname); for (i = 0; i < cfg->dev_no; i++) new_volume->extents[i].svc_id = cfg->devs[i]; new_volume->level = cfg->level; diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index c0099c5a2c..7da7698329 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -96,7 +96,7 @@ errno_t hr_write_meta_to_vol(hr_volume_t *vol) goto error; uuid_encode(&uuid, metadata->uuid); - str_cpy(metadata->devname, 32, vol->devname); + str_cpy(metadata->devname, HR_DEVNAME_LEN, vol->devname); rc = block_write_direct(vol->extents[i].svc_id, HR_META_OFF, HR_META_SIZE, metadata); diff --git a/uspace/srv/bd/hr/superblock.h b/uspace/srv/bd/hr/superblock.h index 66250bd49b..d7fb94062c 100644 --- a/uspace/srv/bd/hr/superblock.h +++ b/uspace/srv/bd/hr/superblock.h @@ -43,6 +43,7 @@ #define HR_DATA_OFF (HR_META_SIZE + HR_META_OFF) #define HR_MAGIC 0x4420492041205248LLU +#define HR_UUID_LEN 16 typedef struct hr_metadata { uint64_t magic; @@ -54,8 +55,8 @@ typedef struct hr_metadata { uint32_t index; /* index of disk in array */ uint32_t strip_size; uint32_t status; /* yet unused */ - uint8_t uuid[16]; - char devname[32]; + uint8_t uuid[HR_UUID_LEN]; + char devname[HR_DEVNAME_LEN]; } hr_metadata_t; extern errno_t hr_write_meta_to_vol(hr_volume_t *); diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index e4d3baa44b..509c7c2d4a 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -55,7 +55,7 @@ typedef struct hr_volume { hr_ops_t hr_ops; bd_srvs_t hr_bds; link_t lvolumes; - char devname[32]; + char devname[HR_DEVNAME_LEN]; hr_extent_t extents[HR_MAXDEVS]; uint64_t nblocks; uint64_t data_blkno; From abc2c4b7a413ed555dcaacfbb6cfbc3a5f4930b0 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 11 Oct 2024 19:57:17 +0200 Subject: [PATCH 031/324] hr: remove big lock, add lock for individual volumes --- uspace/srv/bd/hr/hr.c | 5 ++--- uspace/srv/bd/hr/raid0.c | 13 ++++++------- uspace/srv/bd/hr/raid1.c | 13 ++++++------- uspace/srv/bd/hr/raid4.c | 13 ++++++------- uspace/srv/bd/hr/raid5.c | 13 ++++++------- uspace/srv/bd/hr/var.h | 1 + 6 files changed, 27 insertions(+), 31 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index a9b7a5d38f..c3ffda7026 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -53,7 +53,6 @@ #include "var.h" loc_srv_t *hr_srv; -fibril_mutex_t big_lock; /* for now */ static fibril_mutex_t hr_volumes_lock; static list_t hr_volumes; @@ -205,6 +204,8 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) goto error; } + fibril_mutex_initialize(&new_volume->lock); + rc = new_volume->hr_ops.create(new_volume); if (rc != EOK) goto error; @@ -388,8 +389,6 @@ int main(int argc, char **argv) return 1; } - fibril_mutex_initialize(&big_lock); - fibril_mutex_initialize(&hr_volumes_lock); list_initialize(&hr_volumes); diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index 2b8b27f8e8..077c6fe34b 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -51,7 +51,6 @@ #include "util.h" #include "var.h" -extern fibril_mutex_t big_lock; extern loc_srv_t *hr_srv; static errno_t hr_raid0_bd_open(bd_srvs_t *, bd_srv_t *); @@ -111,7 +110,7 @@ static errno_t hr_raid0_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) if (rc != EOK) return rc; - fibril_mutex_lock(&big_lock); + fibril_mutex_lock(&vol->lock); left = cnt; while (left != 0) { @@ -124,7 +123,7 @@ static errno_t hr_raid0_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) ba++; } - fibril_mutex_unlock(&big_lock); + fibril_mutex_unlock(&vol->lock); return rc; } @@ -143,7 +142,7 @@ static errno_t hr_raid0_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, if (rc != EOK) return rc; - fibril_mutex_lock(&big_lock); + fibril_mutex_lock(&vol->lock); left = cnt; while (left != 0) { @@ -157,7 +156,7 @@ static errno_t hr_raid0_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, ba++; } - fibril_mutex_unlock(&big_lock); + fibril_mutex_unlock(&vol->lock); return rc; } @@ -176,7 +175,7 @@ static errno_t hr_raid0_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, if (rc != EOK) return rc; - fibril_mutex_lock(&big_lock); + fibril_mutex_lock(&vol->lock); left = cnt; while (left != 0) { @@ -190,7 +189,7 @@ static errno_t hr_raid0_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, ba++; } - fibril_mutex_unlock(&big_lock); + fibril_mutex_unlock(&vol->lock); return rc; } diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 33cd6df21f..4aec7b2e85 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -50,7 +50,6 @@ #include "util.h" #include "var.h" -extern fibril_mutex_t big_lock; extern loc_srv_t *hr_srv; static errno_t hr_raid1_bd_open(bd_srvs_t *, bd_srv_t *); @@ -98,7 +97,7 @@ static errno_t hr_raid1_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) hr_add_ba_offset(vol, &ba); - fibril_mutex_lock(&big_lock); + fibril_mutex_lock(&vol->lock); for (i = 0; i < vol->dev_no; i++) { rc = block_sync_cache(vol->extents[i].svc_id, ba, cnt); @@ -106,7 +105,7 @@ static errno_t hr_raid1_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) break; } - fibril_mutex_unlock(&big_lock); + fibril_mutex_unlock(&vol->lock); return rc; } @@ -124,7 +123,7 @@ static errno_t hr_raid1_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, hr_add_ba_offset(vol, &ba); - fibril_mutex_lock(&big_lock); + fibril_mutex_lock(&vol->lock); for (i = 0; i < vol->dev_no; i++) { rc = block_read_direct(vol->extents[i].svc_id, ba, cnt, buf); @@ -132,7 +131,7 @@ static errno_t hr_raid1_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, break; } - fibril_mutex_unlock(&big_lock); + fibril_mutex_unlock(&vol->lock); return rc; } @@ -150,7 +149,7 @@ static errno_t hr_raid1_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, hr_add_ba_offset(vol, &ba); - fibril_mutex_lock(&big_lock); + fibril_mutex_lock(&vol->lock); for (i = 0; i < vol->dev_no; i++) { rc = block_write_direct(vol->extents[i].svc_id, ba, cnt, data); @@ -158,7 +157,7 @@ static errno_t hr_raid1_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, break; } - fibril_mutex_unlock(&big_lock); + fibril_mutex_unlock(&vol->lock); return rc; } diff --git a/uspace/srv/bd/hr/raid4.c b/uspace/srv/bd/hr/raid4.c index b9a6dfe9e0..75f6259944 100644 --- a/uspace/srv/bd/hr/raid4.c +++ b/uspace/srv/bd/hr/raid4.c @@ -51,7 +51,6 @@ #include "util.h" #include "var.h" -extern fibril_mutex_t big_lock; extern loc_srv_t *hr_srv; static errno_t hr_raid4_bd_open(bd_srvs_t *, bd_srv_t *); @@ -156,7 +155,7 @@ static errno_t hr_raid4_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) if (rc != EOK) return rc; - fibril_mutex_lock(&big_lock); + fibril_mutex_lock(&vol->lock); size_t left = cnt; while (left != 0) { @@ -169,7 +168,7 @@ static errno_t hr_raid4_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) ba++; } - fibril_mutex_unlock(&big_lock); + fibril_mutex_unlock(&vol->lock); return rc; } @@ -188,7 +187,7 @@ static errno_t hr_raid4_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, if (rc != EOK) return rc; - fibril_mutex_lock(&big_lock); + fibril_mutex_lock(&vol->lock); size_t left = cnt; while (left != 0) { @@ -202,7 +201,7 @@ static errno_t hr_raid4_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, ba++; } - fibril_mutex_unlock(&big_lock); + fibril_mutex_unlock(&vol->lock); return rc; } @@ -221,7 +220,7 @@ static errno_t hr_raid4_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, if (rc != EOK) return rc; - fibril_mutex_lock(&big_lock); + fibril_mutex_lock(&vol->lock); size_t left = cnt; while (left != 0) { @@ -238,7 +237,7 @@ static errno_t hr_raid4_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, ba++; } - fibril_mutex_unlock(&big_lock); + fibril_mutex_unlock(&vol->lock); return rc; } diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 7db56b7822..d221876046 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -51,7 +51,6 @@ #include "util.h" #include "var.h" -extern fibril_mutex_t big_lock; extern loc_srv_t *hr_srv; static errno_t hr_raid5_bd_open(bd_srvs_t *, bd_srv_t *); @@ -168,7 +167,7 @@ static errno_t hr_raid5_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) if (rc != EOK) return rc; - fibril_mutex_lock(&big_lock); + fibril_mutex_lock(&vol->lock); size_t left = cnt; while (left != 0) { @@ -181,7 +180,7 @@ static errno_t hr_raid5_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) ba++; } - fibril_mutex_unlock(&big_lock); + fibril_mutex_unlock(&vol->lock); return rc; } @@ -200,7 +199,7 @@ static errno_t hr_raid5_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, if (rc != EOK) return rc; - fibril_mutex_lock(&big_lock); + fibril_mutex_lock(&vol->lock); size_t left = cnt; while (left != 0) { @@ -214,7 +213,7 @@ static errno_t hr_raid5_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, ba++; } - fibril_mutex_unlock(&big_lock); + fibril_mutex_unlock(&vol->lock); return rc; } @@ -233,7 +232,7 @@ static errno_t hr_raid5_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, if (rc != EOK) return rc; - fibril_mutex_lock(&big_lock); + fibril_mutex_lock(&vol->lock); size_t left = cnt; while (left != 0) { @@ -250,7 +249,7 @@ static errno_t hr_raid5_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, ba++; } - fibril_mutex_unlock(&big_lock); + fibril_mutex_unlock(&vol->lock); return rc; } diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index 509c7c2d4a..32d9ca7d24 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -55,6 +55,7 @@ typedef struct hr_volume { hr_ops_t hr_ops; bd_srvs_t hr_bds; link_t lvolumes; + fibril_mutex_t lock; char devname[HR_DEVNAME_LEN]; hr_extent_t extents[HR_MAXDEVS]; uint64_t nblocks; From c7b4452008619ae80c4071a65ca13cddffc6b55e Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Wed, 16 Oct 2024 23:54:17 +0200 Subject: [PATCH 032/324] hr: fix xorbuf memory leak --- uspace/srv/bd/hr/raid4.c | 4 +++- uspace/srv/bd/hr/raid5.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/uspace/srv/bd/hr/raid4.c b/uspace/srv/bd/hr/raid4.c index 75f6259944..d7696af116 100644 --- a/uspace/srv/bd/hr/raid4.c +++ b/uspace/srv/bd/hr/raid4.c @@ -96,8 +96,10 @@ static errno_t write_parity(hr_volume_t *vol, uint64_t extent, uint64_t block, return ENOMEM; buf = malloc(vol->bsize); - if (buf == NULL) + if (buf == NULL) { + free(xorbuf); return ENOMEM; + } for (i = 1; i < vol->dev_no; i++) { if (i == extent) { diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index d221876046..d457d1c790 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -96,8 +96,10 @@ static errno_t write_parity(hr_volume_t *vol, uint64_t p_extent, return ENOMEM; buf = malloc(vol->bsize); - if (buf == NULL) + if (buf == NULL) { + free(xorbuf); return ENOMEM; + } for (i = 0; i < vol->dev_no; i++) { if (i == p_extent) From 12321f864af0d771265144ac66e84cc04543249a Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Wed, 16 Oct 2024 23:57:59 +0200 Subject: [PATCH 033/324] hr: fix return value in write_parity() --- uspace/srv/bd/hr/raid4.c | 2 +- uspace/srv/bd/hr/raid5.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uspace/srv/bd/hr/raid4.c b/uspace/srv/bd/hr/raid4.c index d7696af116..b9bb4763a2 100644 --- a/uspace/srv/bd/hr/raid4.c +++ b/uspace/srv/bd/hr/raid4.c @@ -117,7 +117,7 @@ static errno_t write_parity(hr_volume_t *vol, uint64_t extent, uint64_t block, end: free(xorbuf); free(buf); - return EOK; + return rc; } static void raid4_geometry(uint64_t x, hr_volume_t *vol, size_t *extent, diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index d457d1c790..40ee7bd867 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -120,7 +120,7 @@ static errno_t write_parity(hr_volume_t *vol, uint64_t p_extent, end: free(xorbuf); free(buf); - return EOK; + return rc; } static void raid5_geometry(uint64_t x, hr_volume_t *vol, size_t *extent, From 08fa9e8bb82fc45ac297bdf682d35ce3439dc708 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Thu, 17 Oct 2024 00:00:30 +0200 Subject: [PATCH 034/324] hr: style: simplify return value in create functions --- uspace/srv/bd/hr/raid0.c | 4 +--- uspace/srv/bd/hr/raid1.c | 4 +--- uspace/srv/bd/hr/raid4.c | 4 +--- uspace/srv/bd/hr/raid5.c | 4 +--- 4 files changed, 4 insertions(+), 12 deletions(-) diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index 077c6fe34b..875a32a2fb 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -226,10 +226,8 @@ errno_t hr_raid0_create(hr_volume_t *new_volume) new_volume->hr_bds.sarg = new_volume; rc = hr_register_volume(new_volume); - if (rc != EOK) - return rc; - return EOK; + return rc; } errno_t hr_raid0_init(hr_volume_t *vol) diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 4aec7b2e85..4fbefb9112 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -194,10 +194,8 @@ errno_t hr_raid1_create(hr_volume_t *new_volume) new_volume->hr_bds.sarg = new_volume; rc = hr_register_volume(new_volume); - if (rc != EOK) - return rc; - return EOK; + return rc; } errno_t hr_raid1_init(hr_volume_t *vol) diff --git a/uspace/srv/bd/hr/raid4.c b/uspace/srv/bd/hr/raid4.c index b9bb4763a2..31f93cd0d7 100644 --- a/uspace/srv/bd/hr/raid4.c +++ b/uspace/srv/bd/hr/raid4.c @@ -276,10 +276,8 @@ errno_t hr_raid4_create(hr_volume_t *new_volume) new_volume->hr_bds.sarg = new_volume; rc = hr_register_volume(new_volume); - if (rc != EOK) - return rc; - return EOK; + return rc; } errno_t hr_raid4_init(hr_volume_t *vol) diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 40ee7bd867..1826b12a60 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -288,10 +288,8 @@ errno_t hr_raid5_create(hr_volume_t *new_volume) new_volume->hr_bds.sarg = new_volume; rc = hr_register_volume(new_volume); - if (rc != EOK) - return rc; - return EOK; + return rc; } errno_t hr_raid5_init(hr_volume_t *vol) From 6d55e39c08f9ac6a590dc2cce004774672533d4d Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 18 Oct 2024 12:55:42 +0200 Subject: [PATCH 035/324] hrctl: remove disk concatenation option --- uspace/app/hrctl/hrctl.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index 65a85b3ec9..2a6fe88158 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -53,21 +53,20 @@ static const char usage_str[] = "\n" "Options:\n" " -h, --help display this help and exit\n" - " -C, --create-file=path create an array from file,\n" + " -C, --create-file=PATH create an array from file,\n" " sample file at: " HRCTL_SAMPLE_CONFIG_PATH "\n" - " -A, --assemble-file=path create an array from file\n" + " -A, --assemble-file=PATH create an array from file\n" " -s, --status display status of active arrays\n" " -T, --stop stop an active array\n" " -c, --create=NAME create new array\n" " -a, --assemble=NAME assemble an existing array\n" " -n non-zero number of devices\n" " -l, --level=LEVEL set the RAID level,\n" - " valid values: 0, 1, 4, 5, linear\n" + " valid values: 0, 1, 4, 5\n" " -0 striping\n" " -1 mirroring\n" " -4 parity on one extent\n" " -5 distributed parity\n" - " -L linear concatenation\n" "\n" "Example usage:\n" " hrctl --create hr0 -0 -n 2 devices/\\hw\\0 devices/\\hw\\1\n" @@ -160,8 +159,6 @@ static errno_t load_config(const char *path, hr_config_t *cfg) level_str = sif_node_get_attr(narray, "level"); if (level_str == NULL) cfg->level = hr_l_empty; - else if (str_cmp(level_str, "linear") == 0) - cfg->level = hr_l_linear; else cfg->level = strtol(level_str, NULL, 10); @@ -290,10 +287,7 @@ int main(int argc, char **argv) case 'l': if (cfg->level != hr_l_empty) goto bad; - if (str_cmp(optarg, "linear") == 0) - cfg->level = hr_l_linear; - else - cfg->level = strtol(optarg, NULL, 10); + cfg->level = strtol(optarg, NULL, 10); break; case '0': if (cfg->level != hr_l_empty) @@ -315,11 +309,6 @@ int main(int argc, char **argv) goto bad; cfg->level = hr_l_5; break; - case 'L': - if (cfg->level != hr_l_empty) - goto bad; - cfg->level = hr_l_linear; - break; case 'n': cfg->dev_no = strtol(optarg, NULL, 10); if ((int) cfg->dev_no + optind != argc) From 50bed55dd5e0faca9133e9d152967c4d75296bf6 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 18 Oct 2024 16:30:56 +0200 Subject: [PATCH 036/324] hr: rename levels to upper case --- uspace/app/hrctl/hrctl.c | 24 ++++++++++++------------ uspace/lib/device/include/hr.h | 17 ++++++++--------- uspace/lib/device/src/hr.c | 8 ++++---- uspace/srv/bd/hr/hr.c | 12 ++++++------ uspace/srv/bd/hr/raid0.c | 4 ++-- uspace/srv/bd/hr/raid1.c | 4 ++-- uspace/srv/bd/hr/raid4.c | 4 ++-- uspace/srv/bd/hr/raid5.c | 4 ++-- uspace/srv/bd/hr/superblock.c | 2 +- 9 files changed, 39 insertions(+), 40 deletions(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index 2a6fe88158..8de8a5261a 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -158,7 +158,7 @@ static errno_t load_config(const char *path, hr_config_t *cfg) level_str = sif_node_get_attr(narray, "level"); if (level_str == NULL) - cfg->level = hr_l_empty; + cfg->level = HR_LVL_UNKNOWN; else cfg->level = strtol(level_str, NULL, 10); @@ -217,7 +217,7 @@ int main(int argc, char **argv) return 1; retval = 0; - cfg->level = hr_l_empty; + cfg->level = HR_LVL_UNKNOWN; cfg->dev_no = 0; create = assemble = false; @@ -285,29 +285,29 @@ int main(int argc, char **argv) } return 0; case 'l': - if (cfg->level != hr_l_empty) + if (cfg->level != HR_LVL_UNKNOWN) goto bad; cfg->level = strtol(optarg, NULL, 10); break; case '0': - if (cfg->level != hr_l_empty) + if (cfg->level != HR_LVL_UNKNOWN) goto bad; - cfg->level = hr_l_0; + cfg->level = HR_LVL_0; break; case '1': - if (cfg->level != hr_l_empty) + if (cfg->level != HR_LVL_UNKNOWN) goto bad; - cfg->level = hr_l_1; + cfg->level = HR_LVL_1; break; case '4': - if (cfg->level != hr_l_empty) + if (cfg->level != HR_LVL_UNKNOWN) goto bad; - cfg->level = hr_l_4; + cfg->level = HR_LVL_4; break; case '5': - if (cfg->level != hr_l_empty) + if (cfg->level != HR_LVL_UNKNOWN) goto bad; - cfg->level = hr_l_5; + cfg->level = HR_LVL_5; break; case 'n': cfg->dev_no = strtol(optarg, NULL, 10); @@ -324,7 +324,7 @@ int main(int argc, char **argv) if ((create && assemble) || (!create && !assemble)) goto bad; - if (create && cfg->level == hr_l_empty) { + if (create && cfg->level == HR_LVL_UNKNOWN) { printf("hrctl: invalid level, exiting\n"); return 1; } diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index d346fd29a3..5ac9faa974 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -45,19 +45,18 @@ #define HR_DEVNAME_LEN 32 +typedef enum hr_level { + HR_LVL_0 = 0x00, /* striping, no redundancy */ + HR_LVL_1 = 0x01, /* n-way mirroring */ + HR_LVL_4 = 0x04, /* dedicated parity */ + HR_LVL_5 = 0x05, /* distributed parity */ + HR_LVL_UNKNOWN = 0xFF +} hr_level_t; + typedef struct hr { async_sess_t *sess; } hr_t; -typedef enum hr_level { - hr_l_0 = 0, - hr_l_1 = 1, - hr_l_4 = 4, - hr_l_5 = 5, - hr_l_linear = 254, - hr_l_empty = 255 -} hr_level_t; - typedef struct hr_config { char devname[HR_DEVNAME_LEN]; service_id_t devs[HR_MAXDEVS]; diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index aae7c82fb3..1d4bc39c53 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -130,7 +130,7 @@ static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info) printf("devname: %s\n", devname); printf("level: %d\n", vol_info->level); - if (vol_info->level == hr_l_0 || vol_info->level == hr_l_4) { + if (vol_info->level == HR_LVL_0 || vol_info->level == HR_LVL_4) { if (vol_info->strip_size / 1024 < 1) printf("strip size in bytes: %u\n", vol_info->strip_size); @@ -143,7 +143,7 @@ static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info) printf("size in blocks: %lu\n", vol_info->nblocks); printf("block size: %zu\n", vol_info->bsize); - if (vol_info->level == hr_l_4) + if (vol_info->level == HR_LVL_4) printf("extents: [P] [status] [index] [devname]\n"); else printf("extents: [status] [index] [devname]\n"); @@ -152,9 +152,9 @@ static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info) rc = loc_service_get_name(ext->svc_id, &devname); if (rc != EOK) return rc; - if (i == 0 && vol_info->level == hr_l_4) + if (i == 0 && vol_info->level == HR_LVL_4) printf(" P %d %zu %s\n", ext->status, i, devname); - else if (vol_info->level == hr_l_4) + else if (vol_info->level == HR_LVL_4) printf(" %d %zu %s\n", ext->status, i, devname); else printf(" %d %zu %s\n", ext->status, i, devname); diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index c3ffda7026..9a5ffcc820 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -146,10 +146,10 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) new_volume->dev_no = cfg->dev_no; if (assemble) { - if (cfg->level != hr_l_empty) + if (cfg->level != HR_LVL_UNKNOWN) log_msg(LOG_DEFAULT, LVL_WARN, "level manually set when assembling, ingoring"); - new_volume->level = hr_l_empty; + new_volume->level = HR_LVL_UNKNOWN; } rc = hr_init_devs(new_volume); @@ -171,19 +171,19 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) } switch (new_volume->level) { - case hr_l_1: + case HR_LVL_1: new_volume->hr_ops.create = hr_raid1_create; new_volume->hr_ops.init = hr_raid1_init; break; - case hr_l_0: + case HR_LVL_0: new_volume->hr_ops.create = hr_raid0_create; new_volume->hr_ops.init = hr_raid0_init; break; - case hr_l_4: + case HR_LVL_4: new_volume->hr_ops.create = hr_raid4_create; new_volume->hr_ops.init = hr_raid4_init; break; - case hr_l_5: + case HR_LVL_5: new_volume->hr_ops.create = hr_raid5_create; new_volume->hr_ops.init = hr_raid5_init; break; diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index 875a32a2fb..c32cdd6f30 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -213,7 +213,7 @@ errno_t hr_raid0_create(hr_volume_t *new_volume) { errno_t rc; - assert(new_volume->level == hr_l_0); + assert(new_volume->level == HR_LVL_0); if (new_volume->dev_no < 2) { log_msg(LOG_DEFAULT, LVL_ERROR, @@ -236,7 +236,7 @@ errno_t hr_raid0_init(hr_volume_t *vol) size_t bsize; uint64_t total_blkno; - assert(vol->level == hr_l_0); + assert(vol->level == HR_LVL_0); rc = hr_check_devs(vol, &total_blkno, &bsize); if (rc != EOK) diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 4fbefb9112..a18408d487 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -181,7 +181,7 @@ errno_t hr_raid1_create(hr_volume_t *new_volume) { errno_t rc; - assert(new_volume->level == hr_l_1); + assert(new_volume->level == HR_LVL_1); if (new_volume->dev_no < 2) { log_msg(LOG_DEFAULT, LVL_ERROR, @@ -204,7 +204,7 @@ errno_t hr_raid1_init(hr_volume_t *vol) size_t bsize; uint64_t total_blkno; - assert(vol->level == hr_l_1); + assert(vol->level == HR_LVL_1); rc = hr_check_devs(vol, &total_blkno, &bsize); if (rc != EOK) diff --git a/uspace/srv/bd/hr/raid4.c b/uspace/srv/bd/hr/raid4.c index 31f93cd0d7..892fd9fa46 100644 --- a/uspace/srv/bd/hr/raid4.c +++ b/uspace/srv/bd/hr/raid4.c @@ -263,7 +263,7 @@ errno_t hr_raid4_create(hr_volume_t *new_volume) { errno_t rc; - assert(new_volume->level == hr_l_4); + assert(new_volume->level == HR_LVL_4); if (new_volume->dev_no < 3) { log_msg(LOG_DEFAULT, LVL_ERROR, @@ -286,7 +286,7 @@ errno_t hr_raid4_init(hr_volume_t *vol) size_t bsize; uint64_t total_blkno; - assert(vol->level == hr_l_4); + assert(vol->level == HR_LVL_4); rc = hr_check_devs(vol, &total_blkno, &bsize); if (rc != EOK) diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 1826b12a60..66ce81b58d 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -275,7 +275,7 @@ errno_t hr_raid5_create(hr_volume_t *new_volume) { errno_t rc; - assert(new_volume->level == hr_l_5); + assert(new_volume->level == HR_LVL_5); if (new_volume->dev_no < 3) { log_msg(LOG_DEFAULT, LVL_ERROR, @@ -298,7 +298,7 @@ errno_t hr_raid5_init(hr_volume_t *vol) size_t bsize; uint64_t total_blkno; - assert(vol->level == hr_l_5); + assert(vol->level == HR_LVL_5); rc = hr_check_devs(vol, &total_blkno, &bsize); if (rc != EOK) diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index 7da7698329..2e74b57eb9 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -66,7 +66,7 @@ errno_t hr_write_meta_to_vol(hr_volume_t *vol) return ENOMEM; meta_blkno = (HR_META_OFF + HR_META_SIZE); - if (vol->level != hr_l_1) + if (vol->level != HR_LVL_1) meta_blkno *= vol->dev_no; if (vol->nblocks < meta_blkno) { From fad91b9136cd9298b086bc69a485e7c2d5cb822d Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 27 Oct 2024 23:51:08 +0100 Subject: [PATCH 037/324] hr: make bd op functions more compact A single function now handles all bd ops, just the type of IO reuqest is specified in bd op caller. Besides this design being more compact, it can be seen as preparation for workers and parallelization. --- uspace/srv/bd/hr/raid0.c | 94 +++++++++++------------------ uspace/srv/bd/hr/raid1.c | 88 +++++++++++++-------------- uspace/srv/bd/hr/raid4.c | 109 ++++++++++++++-------------------- uspace/srv/bd/hr/raid5.c | 124 +++++++++++++++++---------------------- uspace/srv/bd/hr/var.h | 6 ++ 5 files changed, 180 insertions(+), 241 deletions(-) diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index c32cdd6f30..ce15fd6f10 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -99,13 +99,18 @@ static errno_t hr_raid0_bd_close(bd_srv_t *bd) return EOK; } -static errno_t hr_raid0_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) +static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, + size_t cnt, void *data_read, const void *data_write, size_t size) { hr_volume_t *vol = bd->srvs->sarg; errno_t rc; uint64_t phys_block; size_t extent, left; + if (type == HR_BD_READ || type == HR_BD_WRITE) + if (size < cnt * vol->bsize) + return EINVAL; + rc = hr_check_ba_range(vol, cnt, ba); if (rc != EOK) return rc; @@ -116,81 +121,52 @@ static errno_t hr_raid0_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) while (left != 0) { raid0_geometry(ba, vol, &extent, &phys_block); hr_add_ba_offset(vol, &phys_block); - rc = block_sync_cache(vol->extents[extent].svc_id, phys_block, 1); - if (rc != EOK) + switch (type) { + case HR_BD_SYNC: + rc = block_sync_cache(vol->extents[extent].svc_id, + phys_block, 1); + break; + case HR_BD_READ: + rc = block_read_direct(vol->extents[extent].svc_id, + phys_block, 1, data_read); + data_read = data_read + vol->bsize; break; + case HR_BD_WRITE: + rc = block_write_direct(vol->extents[extent].svc_id, + phys_block, 1, data_write); + data_write = data_write + vol->bsize; + break; + default: + rc = EINVAL; + } + + if (rc != EOK) + goto error; + left--; ba++; } +error: fibril_mutex_unlock(&vol->lock); return rc; } +static errno_t hr_raid0_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) +{ + return hr_raid0_bd_op(HR_BD_SYNC, bd, ba, cnt, NULL, NULL, 0); +} + static errno_t hr_raid0_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, void *buf, size_t size) { - hr_volume_t *vol = bd->srvs->sarg; - errno_t rc; - uint64_t phys_block; - size_t extent, left; - - if (size < cnt * vol->bsize) - return EINVAL; - - rc = hr_check_ba_range(vol, cnt, ba); - if (rc != EOK) - return rc; - - fibril_mutex_lock(&vol->lock); - - left = cnt; - while (left != 0) { - raid0_geometry(ba, vol, &extent, &phys_block); - hr_add_ba_offset(vol, &phys_block); - rc = block_read_direct(vol->extents[extent].svc_id, phys_block, 1, buf); - buf = buf + vol->bsize; - if (rc != EOK) - break; - left--; - ba++; - } - - fibril_mutex_unlock(&vol->lock); - return rc; + return hr_raid0_bd_op(HR_BD_READ, bd, ba, cnt, buf, NULL, size); } static errno_t hr_raid0_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, const void *data, size_t size) { - hr_volume_t *vol = bd->srvs->sarg; - errno_t rc; - uint64_t phys_block; - size_t extent, left; - - if (size < cnt * vol->bsize) - return EINVAL; - - rc = hr_check_ba_range(vol, cnt, ba); - if (rc != EOK) - return rc; - - fibril_mutex_lock(&vol->lock); - - left = cnt; - while (left != 0) { - raid0_geometry(ba, vol, &extent, &phys_block); - hr_add_ba_offset(vol, &phys_block); - rc = block_write_direct(vol->extents[extent].svc_id, phys_block, 1, data); - data = data + vol->bsize; - if (rc != EOK) - break; - left--; - ba++; - } - - fibril_mutex_unlock(&vol->lock); - return rc; + return hr_raid0_bd_op(HR_BD_WRITE, bd, ba, cnt, NULL, data, size); } static errno_t hr_raid0_bd_get_block_size(bd_srv_t *bd, size_t *rsize) diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index a18408d487..60cf6a7826 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -84,13 +84,17 @@ static errno_t hr_raid1_bd_close(bd_srv_t *bd) return EOK; } -static errno_t hr_raid1_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) +static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, + size_t cnt, void *data_read, const void *data_write, size_t size) { hr_volume_t *vol = bd->srvs->sarg; - errno_t rc; size_t i; + if (type == HR_BD_READ || type == HR_BD_WRITE) + if (size < cnt * vol->bsize) + return EINVAL; + rc = hr_check_ba_range(vol, cnt, ba); if (rc != EOK) return rc; @@ -99,66 +103,54 @@ static errno_t hr_raid1_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) fibril_mutex_lock(&vol->lock); - for (i = 0; i < vol->dev_no; i++) { - rc = block_sync_cache(vol->extents[i].svc_id, ba, cnt); - if (rc != EOK) - break; + switch (type) { + case HR_BD_SYNC: + for (i = 0; i < vol->dev_no; i++) { + rc = block_sync_cache(vol->extents[i].svc_id, ba, cnt); + if (rc != EOK) + goto error; + } + break; + case HR_BD_READ: + for (i = 0; i < vol->dev_no; i++) { + rc = block_read_direct(vol->extents[i].svc_id, ba, cnt, + data_read); + if (rc != EOK) + goto error; + } + break; + case HR_BD_WRITE: + for (i = 0; i < vol->dev_no; i++) { + rc = block_write_direct(vol->extents[i].svc_id, ba, cnt, + data_write); + if (rc != EOK) + goto error; + } + break; + default: + rc = EINVAL; } +error: fibril_mutex_unlock(&vol->lock); return rc; } +static errno_t hr_raid1_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) +{ + return hr_raid1_bd_op(HR_BD_SYNC, bd, ba, cnt, NULL, NULL, 0); +} + static errno_t hr_raid1_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, void *buf, size_t size) { - hr_volume_t *vol = bd->srvs->sarg; - - errno_t rc; - size_t i; - - rc = hr_check_ba_range(vol, cnt, ba); - if (rc != EOK) - return rc; - - hr_add_ba_offset(vol, &ba); - - fibril_mutex_lock(&vol->lock); - - for (i = 0; i < vol->dev_no; i++) { - rc = block_read_direct(vol->extents[i].svc_id, ba, cnt, buf); - if (rc != EOK) - break; - } - - fibril_mutex_unlock(&vol->lock); - return rc; + return hr_raid1_bd_op(HR_BD_READ, bd, ba, cnt, buf, NULL, size); } static errno_t hr_raid1_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, const void *data, size_t size) { - hr_volume_t *vol = bd->srvs->sarg; - - errno_t rc; - size_t i; - - rc = hr_check_ba_range(vol, cnt, ba); - if (rc != EOK) - return rc; - - hr_add_ba_offset(vol, &ba); - - fibril_mutex_lock(&vol->lock); - - for (i = 0; i < vol->dev_no; i++) { - rc = block_write_direct(vol->extents[i].svc_id, ba, cnt, data); - if (rc != EOK) - break; - } - - fibril_mutex_unlock(&vol->lock); - return rc; + return hr_raid1_bd_op(HR_BD_WRITE, bd, ba, cnt, NULL, data, size); } static errno_t hr_raid1_bd_get_block_size(bd_srv_t *bd, size_t *rsize) diff --git a/uspace/srv/bd/hr/raid4.c b/uspace/srv/bd/hr/raid4.c index 892fd9fa46..9cf043d7f0 100644 --- a/uspace/srv/bd/hr/raid4.c +++ b/uspace/srv/bd/hr/raid4.c @@ -105,7 +105,8 @@ static errno_t write_parity(hr_volume_t *vol, uint64_t extent, uint64_t block, if (i == extent) { xor(xorbuf, data, vol->bsize); } else { - rc = block_read_direct(vol->extents[i].svc_id, block, 1, buf); + rc = block_read_direct(vol->extents[i].svc_id, block, 1, + buf); if (rc != EOK) goto end; xor(xorbuf, buf, vol->bsize); @@ -146,12 +147,17 @@ static errno_t hr_raid4_bd_close(bd_srv_t *bd) return EOK; } -static errno_t hr_raid4_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) +static errno_t hr_raid4_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, + size_t cnt, void *data_read, const void *data_write, size_t size) { hr_volume_t *vol = bd->srvs->sarg; errno_t rc; uint64_t phys_block; - size_t extent; + size_t extent, left; + + if (type == HR_BD_READ || type == HR_BD_WRITE) + if (size < cnt * vol->bsize) + return EINVAL; rc = hr_check_ba_range(vol, cnt, ba); if (rc != EOK) @@ -159,88 +165,61 @@ static errno_t hr_raid4_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) fibril_mutex_lock(&vol->lock); - size_t left = cnt; + left = cnt; while (left != 0) { raid4_geometry(ba, vol, &extent, &phys_block); hr_add_ba_offset(vol, &phys_block); - rc = block_sync_cache(vol->extents[extent].svc_id, phys_block, 1); - if (rc != EOK) + switch (type) { + case HR_BD_SYNC: + rc = block_sync_cache(vol->extents[extent].svc_id, + phys_block, 1); + break; + case HR_BD_READ: + rc = block_read_direct(vol->extents[extent].svc_id, + phys_block, 1, data_read); + data_read = data_read + vol->bsize; break; + case HR_BD_WRITE: + rc = block_write_direct(vol->extents[extent].svc_id, + phys_block, 1, data_write); + if (rc != EOK) + goto error; + rc = write_parity(vol, extent, phys_block, data_write); + if (rc != EOK) + goto error; + data_write = data_write + vol->bsize; + break; + default: + rc = EINVAL; + } + + if (rc != EOK) + goto error; + left--; ba++; } +error: fibril_mutex_unlock(&vol->lock); return rc; } +static errno_t hr_raid4_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) +{ + return hr_raid4_bd_op(HR_BD_SYNC, bd, ba, cnt, NULL, NULL, 0); +} + static errno_t hr_raid4_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, void *buf, size_t size) { - hr_volume_t *vol = bd->srvs->sarg; - errno_t rc; - uint64_t phys_block; - size_t extent; - - if (size < cnt * vol->bsize) - return EINVAL; - - rc = hr_check_ba_range(vol, cnt, ba); - if (rc != EOK) - return rc; - - fibril_mutex_lock(&vol->lock); - - size_t left = cnt; - while (left != 0) { - raid4_geometry(ba, vol, &extent, &phys_block); - hr_add_ba_offset(vol, &phys_block); - rc = block_read_direct(vol->extents[extent].svc_id, phys_block, 1, buf); - buf = buf + vol->bsize; - if (rc != EOK) - break; - left--; - ba++; - } - - fibril_mutex_unlock(&vol->lock); - return rc; + return hr_raid4_bd_op(HR_BD_READ, bd, ba, cnt, buf, NULL, size); } static errno_t hr_raid4_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, const void *data, size_t size) { - hr_volume_t *vol = bd->srvs->sarg; - errno_t rc; - uint64_t phys_block; - size_t extent; - - if (size < cnt * vol->bsize) - return EINVAL; - - rc = hr_check_ba_range(vol, cnt, ba); - if (rc != EOK) - return rc; - - fibril_mutex_lock(&vol->lock); - - size_t left = cnt; - while (left != 0) { - raid4_geometry(ba, vol, &extent, &phys_block); - hr_add_ba_offset(vol, &phys_block); - rc = block_write_direct(vol->extents[extent].svc_id, phys_block, 1, data); - if (rc != EOK) - break; - rc = write_parity(vol, extent, phys_block, data); - if (rc != EOK) - break; - data = data + vol->bsize; - left--; - ba++; - } - - fibril_mutex_unlock(&vol->lock); - return rc; + return hr_raid4_bd_op(HR_BD_WRITE, bd, ba, cnt, NULL, data, size); } static errno_t hr_raid4_bd_get_block_size(bd_srv_t *bd, size_t *rsize) diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 66ce81b58d..9be7d96da1 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -108,14 +108,16 @@ static errno_t write_parity(hr_volume_t *vol, uint64_t p_extent, if (i == extent) { xor(xorbuf, data, vol->bsize); } else { - rc = block_read_direct(vol->extents[i].svc_id, block, 1, buf); + rc = block_read_direct(vol->extents[i].svc_id, block, 1, + buf); if (rc != EOK) goto end; xor(xorbuf, buf, vol->bsize); } } - rc = block_write_direct(vol->extents[p_extent].svc_id, block, 1, xorbuf); + rc = block_write_direct(vol->extents[p_extent].svc_id, block, 1, + xorbuf); end: free(xorbuf); @@ -158,12 +160,17 @@ static errno_t hr_raid5_bd_close(bd_srv_t *bd) return EOK; } -static errno_t hr_raid5_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) +static errno_t hr_raid5_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, + size_t cnt, void *data_read, const void *data_write, size_t size) { hr_volume_t *vol = bd->srvs->sarg; errno_t rc; - uint64_t phys_block; - size_t extent; + uint64_t phys_block, p_extent; + size_t extent, left; + + if (type == HR_BD_READ || type == HR_BD_WRITE) + if (size < cnt * vol->bsize) + return EINVAL; rc = hr_check_ba_range(vol, cnt, ba); if (rc != EOK) @@ -171,88 +178,67 @@ static errno_t hr_raid5_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) fibril_mutex_lock(&vol->lock); - size_t left = cnt; + left = cnt; while (left != 0) { - raid5_geometry(ba, vol, &extent, &phys_block, NULL); - hr_add_ba_offset(vol, &phys_block); - rc = block_sync_cache(vol->extents[extent].svc_id, phys_block, 1); - if (rc != EOK) + switch (type) { + case HR_BD_SYNC: + raid5_geometry(ba, vol, &extent, &phys_block, NULL); + hr_add_ba_offset(vol, &phys_block); + rc = block_sync_cache(vol->extents[extent].svc_id, + phys_block, 1); + break; + case HR_BD_READ: + raid5_geometry(ba, vol, &extent, &phys_block, NULL); + hr_add_ba_offset(vol, &phys_block); + rc = block_read_direct(vol->extents[extent].svc_id, + phys_block, 1, data_read); + data_read = data_read + vol->bsize; + break; + case HR_BD_WRITE: + raid5_geometry(ba, vol, &extent, &phys_block, + &p_extent); + hr_add_ba_offset(vol, &phys_block); + rc = block_write_direct(vol->extents[extent].svc_id, + phys_block, 1, data_write); + if (rc != EOK) + goto error; + rc = write_parity(vol, p_extent, extent, phys_block, + data_write); + if (rc != EOK) + goto error; + data_write = data_write + vol->bsize; break; + default: + rc = EINVAL; + } + + if (rc != EOK) + goto error; + left--; ba++; } +error: fibril_mutex_unlock(&vol->lock); return rc; } +static errno_t hr_raid5_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) +{ + return hr_raid5_bd_op(HR_BD_SYNC, bd, ba, cnt, NULL, NULL, 0); +} + static errno_t hr_raid5_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, void *buf, size_t size) { - hr_volume_t *vol = bd->srvs->sarg; - errno_t rc; - uint64_t phys_block; - size_t extent; - - if (size < cnt * vol->bsize) - return EINVAL; - - rc = hr_check_ba_range(vol, cnt, ba); - if (rc != EOK) - return rc; - - fibril_mutex_lock(&vol->lock); - - size_t left = cnt; - while (left != 0) { - raid5_geometry(ba, vol, &extent, &phys_block, NULL); - hr_add_ba_offset(vol, &phys_block); - rc = block_read_direct(vol->extents[extent].svc_id, phys_block, 1, buf); - buf = buf + vol->bsize; - if (rc != EOK) - break; - left--; - ba++; - } - - fibril_mutex_unlock(&vol->lock); - return rc; + return hr_raid5_bd_op(HR_BD_READ, bd, ba, cnt, buf, NULL, size); } static errno_t hr_raid5_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, const void *data, size_t size) { - hr_volume_t *vol = bd->srvs->sarg; - errno_t rc; - uint64_t phys_block, p_extent; - size_t extent; - - if (size < cnt * vol->bsize) - return EINVAL; - - rc = hr_check_ba_range(vol, cnt, ba); - if (rc != EOK) - return rc; - - fibril_mutex_lock(&vol->lock); - - size_t left = cnt; - while (left != 0) { - raid5_geometry(ba, vol, &extent, &phys_block, &p_extent); - hr_add_ba_offset(vol, &phys_block); - rc = block_write_direct(vol->extents[extent].svc_id, phys_block, 1, data); - if (rc != EOK) - break; - rc = write_parity(vol, p_extent, extent, phys_block, data); - if (rc != EOK) - break; - data = data + vol->bsize; - left--; - ba++; - } - - fibril_mutex_unlock(&vol->lock); - return rc; + return hr_raid5_bd_op(HR_BD_WRITE, bd, ba, cnt, NULL, data, size); } static errno_t hr_raid5_bd_get_block_size(bd_srv_t *bd, size_t *rsize) diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index 32d9ca7d24..264909b98a 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -68,6 +68,12 @@ typedef struct hr_volume { hr_level_t level; } hr_volume_t; +typedef enum { + HR_BD_SYNC, + HR_BD_READ, + HR_BD_WRITE +} hr_bd_op_type_t; + extern errno_t hr_init_devs(hr_volume_t *); extern void hr_fini_devs(hr_volume_t *); From 76cd345cd72977703548c1feb838664ee5b146ab Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 28 Oct 2024 12:23:47 +0100 Subject: [PATCH 038/324] bdwrite: write as many blocks as possible at once --- uspace/app/bdwrite/bdwrite.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/uspace/app/bdwrite/bdwrite.c b/uspace/app/bdwrite/bdwrite.c index 4ded5d2e04..82cea328a2 100644 --- a/uspace/app/bdwrite/bdwrite.c +++ b/uspace/app/bdwrite/bdwrite.c @@ -39,6 +39,7 @@ #include #include #include +#include static void usage(void); @@ -105,21 +106,31 @@ int main(int argc, char **argv) return 1; } - uint8_t *buf = calloc(1, bsize); - for (size_t i = 0; i < blkcnt; i++) { - memset(buf, (i + 1) % 0x100, bsize); - rc = block_write_direct(dev, i + off, 1, buf); + uint64_t to_alloc = min(DATA_XFER_LIMIT, bsize * blkcnt); + uint8_t *buf = calloc(to_alloc / bsize, bsize); + if (buf == NULL) { + rc = ENOMEM; + goto end; + } + uint64_t left = blkcnt; + while (left > 0) { + uint64_t blks_to_write = min(to_alloc / bsize, left); + uint8_t *ptr = buf; + for (size_t i = 0; i < blks_to_write; i++) { + memset(ptr, (i + 1) % 0x100, bsize); + ptr = (uint8_t *)((uintptr_t) ptr + bsize); + } + rc = block_write_direct(dev, off, blks_to_write, buf); if (rc != EOK) { printf("bdwrite: error writing to \"%s\"\n", name); - free(buf); - block_fini(dev); - return 1; + goto end; } + left -= blks_to_write; } - +end: free(buf); block_fini(dev); - return 0; + return rc; bad: usage(); return 0; From 978130a335e8e02a54dd7ff837eccde455df0feb Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 28 Oct 2024 17:03:24 +0100 Subject: [PATCH 039/324] hr: optimize RAID 0, 4, 5 to write whole strip --- uspace/srv/bd/hr/raid0.c | 47 ++++++++-------- uspace/srv/bd/hr/raid4.c | 86 +++++++++++++++------------- uspace/srv/bd/hr/raid5.c | 119 ++++++++++++++++++++------------------- 3 files changed, 131 insertions(+), 121 deletions(-) diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index ce15fd6f10..006a82c5af 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -73,20 +73,6 @@ static bd_ops_t hr_raid0_bd_ops = { .get_num_blocks = hr_raid0_bd_get_num_blocks }; -static void raid0_geometry(uint64_t x, hr_volume_t *vol, size_t *extent, - uint64_t *phys_block) -{ - uint64_t N = vol->dev_no; /* extents */ - uint64_t L = vol->strip_size / vol->bsize; /* size of strip in blocks */ - - uint64_t i = (x / L) % N; /* extent */ - uint64_t j = (x / L) / N; /* stripe */ - uint64_t k = x % L; /* strip offset */ - - *extent = i; - *phys_block = j * L + k; -} - static errno_t hr_raid0_bd_open(bd_srvs_t *bds, bd_srv_t *bd) { log_msg(LOG_DEFAULT, LVL_NOTE, "hr_bd_open()"); @@ -105,7 +91,7 @@ static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, hr_volume_t *vol = bd->srvs->sarg; errno_t rc; uint64_t phys_block; - size_t extent, left; + size_t left; if (type == HR_BD_READ || type == HR_BD_WRITE) if (size < cnt * vol->bsize) @@ -115,36 +101,49 @@ static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, if (rc != EOK) return rc; + uint64_t strip_size = vol->strip_size / vol->bsize; /* in blocks */ + uint64_t stripe = ba / strip_size; /* stripe number */ + uint64_t extent = stripe % vol->dev_no; + uint64_t ext_stripe = stripe / vol->dev_no; /* stripe level */ + uint64_t strip_off = ba % strip_size; /* strip offset */ + fibril_mutex_lock(&vol->lock); left = cnt; while (left != 0) { - raid0_geometry(ba, vol, &extent, &phys_block); + phys_block = ext_stripe * strip_size + strip_off; + cnt = min(left, strip_size - strip_off); hr_add_ba_offset(vol, &phys_block); switch (type) { case HR_BD_SYNC: rc = block_sync_cache(vol->extents[extent].svc_id, - phys_block, 1); + phys_block, cnt); break; case HR_BD_READ: rc = block_read_direct(vol->extents[extent].svc_id, - phys_block, 1, data_read); - data_read = data_read + vol->bsize; + phys_block, cnt, data_read); + data_read = (void *) ((uintptr_t) data_read + + (vol->bsize * cnt)); break; case HR_BD_WRITE: rc = block_write_direct(vol->extents[extent].svc_id, - phys_block, 1, data_write); - data_write = data_write + vol->bsize; + phys_block, cnt, data_write); + data_write = (void *) ((uintptr_t) data_write + + (vol->bsize * cnt)); break; default: rc = EINVAL; } - if (rc != EOK) goto error; - left--; - ba++; + left -= cnt; + strip_off = 0; + extent++; + if (extent >= vol->dev_no) { + ext_stripe++; + extent = 0; + } } error: diff --git a/uspace/srv/bd/hr/raid4.c b/uspace/srv/bd/hr/raid4.c index 9cf043d7f0..fcf1489319 100644 --- a/uspace/srv/bd/hr/raid4.c +++ b/uspace/srv/bd/hr/raid4.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -84,14 +85,14 @@ static void xor(void *dst, const void *src, size_t size) } static errno_t write_parity(hr_volume_t *vol, uint64_t extent, uint64_t block, - const void *data) + const void *data, size_t cnt) { errno_t rc; - size_t i; + size_t i, j; void *xorbuf; void *buf; - xorbuf = calloc(1, vol->bsize); + xorbuf = malloc(vol->bsize); if (xorbuf == NULL) return ENOMEM; @@ -101,40 +102,32 @@ static errno_t write_parity(hr_volume_t *vol, uint64_t extent, uint64_t block, return ENOMEM; } - for (i = 1; i < vol->dev_no; i++) { - if (i == extent) { - xor(xorbuf, data, vol->bsize); - } else { - rc = block_read_direct(vol->extents[i].svc_id, block, 1, - buf); - if (rc != EOK) - goto end; - xor(xorbuf, buf, vol->bsize); + for (j = 0; j < cnt; j++) { + memset(xorbuf, 0, vol->bsize); + for (i = 1; i < vol->dev_no; i++) { + if (i == extent) { + xor(xorbuf, data, vol->bsize); + } else { + rc = block_read_direct(vol->extents[i].svc_id, + block, 1, buf); + if (rc != EOK) + goto end; + xor(xorbuf, buf, vol->bsize); + } } + rc = block_write_direct(vol->extents[0].svc_id, block, 1, + xorbuf); + if (rc != EOK) + goto end; + data = (void *) ((uintptr_t) data + vol->bsize); + block++; } - - rc = block_write_direct(vol->extents[0].svc_id, block, 1, xorbuf); - end: free(xorbuf); free(buf); return rc; } -static void raid4_geometry(uint64_t x, hr_volume_t *vol, size_t *extent, - uint64_t *phys_block) -{ - uint64_t N = vol->dev_no; /* extents */ - uint64_t L = vol->strip_size / vol->bsize; /* size of strip in blocks */ - - uint64_t i = ((x / L) % (N - 1)) + 1; /* extent */ - uint64_t j = (x / L) / (N - 1); /* stripe */ - uint64_t k = x % L; /* strip offset */ - - *extent = i; - *phys_block = j * L + k; -} - static errno_t hr_raid4_bd_open(bd_srvs_t *bds, bd_srv_t *bd) { log_msg(LOG_DEFAULT, LVL_NOTE, "hr_bd_open()"); @@ -153,7 +146,7 @@ static errno_t hr_raid4_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, hr_volume_t *vol = bd->srvs->sarg; errno_t rc; uint64_t phys_block; - size_t extent, left; + size_t left; if (type == HR_BD_READ || type == HR_BD_WRITE) if (size < cnt * vol->bsize) @@ -163,31 +156,41 @@ static errno_t hr_raid4_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, if (rc != EOK) return rc; + uint64_t strip_size = vol->strip_size / vol->bsize; /* in blocks */ + uint64_t stripe = (ba / strip_size); /* stripe number */ + uint64_t extent = (stripe % (vol->dev_no - 1)) + 1; + uint64_t ext_stripe = stripe / (vol->dev_no - 1); /* stripe level */ + uint64_t strip_off = ba % strip_size; /* strip offset */ + fibril_mutex_lock(&vol->lock); left = cnt; while (left != 0) { - raid4_geometry(ba, vol, &extent, &phys_block); + phys_block = ext_stripe * strip_size + strip_off; + cnt = min(left, strip_size - strip_off); hr_add_ba_offset(vol, &phys_block); switch (type) { case HR_BD_SYNC: rc = block_sync_cache(vol->extents[extent].svc_id, - phys_block, 1); + phys_block, cnt); break; case HR_BD_READ: rc = block_read_direct(vol->extents[extent].svc_id, - phys_block, 1, data_read); - data_read = data_read + vol->bsize; + phys_block, cnt, data_read); + data_read = (void *) ((uintptr_t) data_read + + (vol->bsize * cnt)); break; case HR_BD_WRITE: rc = block_write_direct(vol->extents[extent].svc_id, - phys_block, 1, data_write); + phys_block, cnt, data_write); if (rc != EOK) goto error; - rc = write_parity(vol, extent, phys_block, data_write); + rc = write_parity(vol, extent, phys_block, data_write, + cnt); if (rc != EOK) goto error; - data_write = data_write + vol->bsize; + data_write = (void *) ((uintptr_t) data_write + + (vol->bsize * cnt)); break; default: rc = EINVAL; @@ -196,8 +199,13 @@ static errno_t hr_raid4_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, if (rc != EOK) goto error; - left--; - ba++; + left -= cnt; + strip_off = 0; + extent++; + if (extent >= vol->dev_no) { + ext_stripe++; + extent = 1; + } } error: diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 9be7d96da1..70a1e7acc5 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -84,14 +85,14 @@ static void xor(void *dst, const void *src, size_t size) } static errno_t write_parity(hr_volume_t *vol, uint64_t p_extent, - uint64_t extent, uint64_t block, const void *data) + uint64_t extent, uint64_t block, const void *data, size_t cnt) { errno_t rc; - size_t i; + size_t i, j; void *xorbuf; void *buf; - xorbuf = calloc(1, vol->bsize); + xorbuf = malloc(vol->bsize); if (xorbuf == NULL) return ENOMEM; @@ -101,23 +102,30 @@ static errno_t write_parity(hr_volume_t *vol, uint64_t p_extent, return ENOMEM; } - for (i = 0; i < vol->dev_no; i++) { - if (i == p_extent) - continue; - - if (i == extent) { - xor(xorbuf, data, vol->bsize); - } else { - rc = block_read_direct(vol->extents[i].svc_id, block, 1, - buf); - if (rc != EOK) - goto end; - xor(xorbuf, buf, vol->bsize); + for (j = 0; j < cnt; j++) { + memset(xorbuf, 0, vol->bsize); + for (i = 0; i < vol->dev_no; i++) { + if (i == p_extent) + continue; + + if (i == extent) { + xor(xorbuf, data, vol->bsize); + } else { + rc = block_read_direct(vol->extents[i].svc_id, + block, 1, buf); + if (rc != EOK) + goto end; + xor(xorbuf, buf, vol->bsize); + } } - } - rc = block_write_direct(vol->extents[p_extent].svc_id, block, 1, - xorbuf); + rc = block_write_direct(vol->extents[p_extent].svc_id, block, 1, + xorbuf); + if (rc != EOK) + goto end; + data = (void *) ((uintptr_t) data + vol->bsize); + block++; + } end: free(xorbuf); @@ -125,29 +133,6 @@ static errno_t write_parity(hr_volume_t *vol, uint64_t p_extent, return rc; } -static void raid5_geometry(uint64_t x, hr_volume_t *vol, size_t *extent, - uint64_t *phys_block, uint64_t *p_extent) -{ - uint64_t N = vol->dev_no; /* extents */ - uint64_t L = vol->strip_size / vol->bsize; /* size of strip in blocks */ - - uint64_t p = ((x / L) / (N - 1)) % N; - - uint64_t i; /* extent */ - if (((x / L) % (N - 1)) < p) - i = (x / L) % (N - 1); - else - i = ((x / L) % (N - 1)) + 1; - - uint64_t j = (x / L) / (N - 1); /* stripe */ - uint64_t k = x % L; /* strip offset */ - - *extent = i; - *phys_block = j * L + k; - if (p_extent != NULL) - *p_extent = p; -} - static errno_t hr_raid5_bd_open(bd_srvs_t *bds, bd_srv_t *bd) { log_msg(LOG_DEFAULT, LVL_NOTE, "hr_bd_open()"); @@ -165,8 +150,8 @@ static errno_t hr_raid5_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, { hr_volume_t *vol = bd->srvs->sarg; errno_t rc; - uint64_t phys_block, p_extent; - size_t extent, left; + uint64_t phys_block; + size_t left; if (type == HR_BD_READ || type == HR_BD_WRITE) if (size < cnt * vol->bsize) @@ -176,37 +161,46 @@ static errno_t hr_raid5_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, if (rc != EOK) return rc; + uint64_t strip_size = vol->strip_size / vol->bsize; /* in blocks */ + uint64_t stripe = (ba / strip_size); /* stripe number */ + uint64_t p_extent = (stripe / (vol->dev_no - 1)) % vol->dev_no; /* parity extent */ + uint64_t extent; + if ((stripe % (vol->dev_no - 1)) < p_extent) + extent = (stripe % (vol->dev_no - 1)); + else + extent = ((stripe % (vol->dev_no - 1)) + 1); + uint64_t ext_stripe = stripe / (vol->dev_no - 1); /* stripe level */ + uint64_t strip_off = ba % strip_size; /* strip offset */ + fibril_mutex_lock(&vol->lock); left = cnt; while (left != 0) { + phys_block = ext_stripe * strip_size + strip_off; + cnt = min(left, strip_size - strip_off); + hr_add_ba_offset(vol, &phys_block); switch (type) { case HR_BD_SYNC: - raid5_geometry(ba, vol, &extent, &phys_block, NULL); - hr_add_ba_offset(vol, &phys_block); rc = block_sync_cache(vol->extents[extent].svc_id, - phys_block, 1); + phys_block, cnt); break; case HR_BD_READ: - raid5_geometry(ba, vol, &extent, &phys_block, NULL); - hr_add_ba_offset(vol, &phys_block); rc = block_read_direct(vol->extents[extent].svc_id, - phys_block, 1, data_read); - data_read = data_read + vol->bsize; + phys_block, cnt, data_read); + data_read = (void *) ((uintptr_t) data_read + + (vol->bsize * cnt)); break; case HR_BD_WRITE: - raid5_geometry(ba, vol, &extent, &phys_block, - &p_extent); - hr_add_ba_offset(vol, &phys_block); rc = block_write_direct(vol->extents[extent].svc_id, - phys_block, 1, data_write); + phys_block, cnt, data_write); if (rc != EOK) goto error; rc = write_parity(vol, p_extent, extent, phys_block, - data_write); + data_write, cnt); if (rc != EOK) goto error; - data_write = data_write + vol->bsize; + data_write = (void *) ((uintptr_t) data_write + + (vol->bsize * cnt)); break; default: rc = EINVAL; @@ -215,8 +209,17 @@ static errno_t hr_raid5_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, if (rc != EOK) goto error; - left--; - ba++; + left -= cnt; + strip_off = 0; + if (extent + 1 >= vol->dev_no || + (extent + 1 == p_extent && p_extent + 1 >= vol->dev_no)) + ext_stripe++; + stripe++; + p_extent = (stripe / (vol->dev_no - 1)) % vol->dev_no; /* parity extent */ + if ((stripe % (vol->dev_no - 1)) < p_extent) + extent = (stripe % (vol->dev_no - 1)); + else + extent = ((stripe % (vol->dev_no - 1)) + 1); } error: From 4dd650a1739298feb50529a1e16eff9ca9385a3e Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 28 Oct 2024 17:35:38 +0100 Subject: [PATCH 040/324] hr: fix memory leaks in hr_create_srv() --- uspace/srv/bd/hr/hr.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 9a5ffcc820..c7bbf12fdd 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -127,6 +127,7 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) rc = async_data_write_finalize(&call, cfg, size); if (rc != EOK) { + free(cfg); async_answer_0(&call, rc); async_answer_0(icall, rc); return; @@ -155,6 +156,7 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) rc = hr_init_devs(new_volume); if (rc != EOK) { free(cfg); + free(new_volume); async_answer_0(icall, rc); return; } @@ -230,6 +232,7 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) error: free(cfg); hr_fini_devs(new_volume); + free(new_volume); async_answer_0(icall, rc); } From b4227183682edee60deeac2c4a795ed32e05bc0f Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 28 Oct 2024 18:42:31 +0100 Subject: [PATCH 041/324] hr: sort extents based on metadata index --- uspace/srv/bd/hr/superblock.c | 37 +++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index 2e74b57eb9..751ae42b42 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -111,6 +111,16 @@ errno_t hr_write_meta_to_vol(hr_volume_t *vol) return rc; } +static errno_t validate_meta(hr_metadata_t *md) +{ + if (uint64_t_le2host(md->magic) != HR_MAGIC) { + printf("invalid magic\n"); + return EINVAL; + } + return EOK; +} + + errno_t hr_get_vol_from_meta(hr_config_t *cfg, hr_volume_t *new_volume) { log_msg(LOG_DEFAULT, LVL_NOTE, "hr_get_vol_from_meta()"); @@ -122,18 +132,25 @@ errno_t hr_get_vol_from_meta(hr_config_t *cfg, hr_volume_t *new_volume) if (metadata == NULL) return ENOMEM; - /* for now assume metadata are in sync across extents */ - rc = read_metadata(cfg->devs[0], metadata); - if (rc != EOK) - goto end; + uint32_t md_order[HR_MAXDEVS] = { 0 }; + for (size_t i = 0; i < cfg->dev_no; i++) { + rc = read_metadata(cfg->devs[i], metadata); + if (rc != EOK) + goto end; + rc = validate_meta(metadata); + if (rc != EOK) + goto end; + md_order[i] = uint32_t_le2host(metadata->index); + } - /* TODO: sort new_volume->extents according to metadata extent index */ + for (size_t i = 0; i < cfg->dev_no; i++) + for (size_t j = 0; j < cfg->dev_no; j++) + if (i == md_order[j]) + new_volume->extents[i].svc_id = cfg->devs[j]; - if (uint64_t_le2host(metadata->magic) != HR_MAGIC) { - printf("invalid magic\n"); - rc = EINVAL; - goto end; - } + /* + * still assume metadata are in sync across extents + */ new_volume->level = uint32_t_le2host(metadata->level); new_volume->dev_no = uint32_t_le2host(metadata->extent_no); From 066fed91b44c9a5ffe07cb5752c950d683723ca9 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 28 Oct 2024 19:10:45 +0100 Subject: [PATCH 042/324] hr: refactor metadata reading --- uspace/srv/bd/hr/hr.c | 2 +- uspace/srv/bd/hr/superblock.c | 42 +++++++++++++++++++---------------- uspace/srv/bd/hr/superblock.h | 2 +- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index c7bbf12fdd..1e67b09d21 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -167,7 +167,7 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) if (rc != EOK) goto error; - rc = hr_get_vol_from_meta(cfg, new_volume); + rc = hr_fill_vol_from_meta(new_volume); if (rc != EOK) goto error; } diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index 751ae42b42..a661ec1797 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -121,20 +121,25 @@ static errno_t validate_meta(hr_metadata_t *md) } -errno_t hr_get_vol_from_meta(hr_config_t *cfg, hr_volume_t *new_volume) +errno_t hr_fill_vol_from_meta(hr_volume_t *vol) { log_msg(LOG_DEFAULT, LVL_NOTE, "hr_get_vol_from_meta()"); errno_t rc; hr_metadata_t *metadata; - metadata = calloc(1, HR_META_SIZE * new_volume->bsize); + metadata = calloc(1, HR_META_SIZE * vol->bsize); if (metadata == NULL) return ENOMEM; + service_id_t cfg_svc_id_order[HR_MAXDEVS] = { 0 }; + for (size_t i = 0; i < vol->dev_no; i++) + cfg_svc_id_order[i] = vol->extents[i].svc_id; + + uint32_t md_order[HR_MAXDEVS] = { 0 }; - for (size_t i = 0; i < cfg->dev_no; i++) { - rc = read_metadata(cfg->devs[i], metadata); + for (size_t i = 0; i < vol->dev_no; i++) { + rc = read_metadata(cfg_svc_id_order[i], metadata); if (rc != EOK) goto end; rc = validate_meta(metadata); @@ -143,34 +148,33 @@ errno_t hr_get_vol_from_meta(hr_config_t *cfg, hr_volume_t *new_volume) md_order[i] = uint32_t_le2host(metadata->index); } - for (size_t i = 0; i < cfg->dev_no; i++) - for (size_t j = 0; j < cfg->dev_no; j++) + for (size_t i = 0; i < vol->dev_no; i++) + for (size_t j = 0; j < vol->dev_no; j++) if (i == md_order[j]) - new_volume->extents[i].svc_id = cfg->devs[j]; + vol->extents[i].svc_id = cfg_svc_id_order[j]; /* * still assume metadata are in sync across extents */ - new_volume->level = uint32_t_le2host(metadata->level); - new_volume->dev_no = uint32_t_le2host(metadata->extent_no); - new_volume->nblocks = uint64_t_le2host(metadata->nblocks); - new_volume->data_blkno = uint64_t_le2host(metadata->data_blkno); - new_volume->data_offset = uint32_t_le2host(metadata->data_offset); - new_volume->strip_size = uint32_t_le2host(metadata->strip_size); - - if (new_volume->dev_no != cfg->dev_no) { + if (vol->dev_no != uint32_t_le2host(metadata->extent_no)) { log_msg(LOG_DEFAULT, LVL_ERROR, - "number of divices in array differ: specified %zu, metadata states %zu", - cfg->dev_no, new_volume->dev_no); + "number of divices in array differ: specified %zu, metadata states %u", + vol->dev_no, uint32_t_le2host(metadata->extent_no)); rc = EINVAL; goto end; } - if (str_cmp(metadata->devname, new_volume->devname) != 0) { + vol->level = uint32_t_le2host(metadata->level); + vol->nblocks = uint64_t_le2host(metadata->nblocks); + vol->data_blkno = uint64_t_le2host(metadata->data_blkno); + vol->data_offset = uint32_t_le2host(metadata->data_offset); + vol->strip_size = uint32_t_le2host(metadata->strip_size); + + if (str_cmp(metadata->devname, vol->devname) != 0) { log_msg(LOG_DEFAULT, LVL_NOTE, "devname on metadata (%s) and config (%s) differ, using config", - metadata->devname, new_volume->devname); + metadata->devname, vol->devname); } end: free(metadata); diff --git a/uspace/srv/bd/hr/superblock.h b/uspace/srv/bd/hr/superblock.h index d7fb94062c..c6e74f852c 100644 --- a/uspace/srv/bd/hr/superblock.h +++ b/uspace/srv/bd/hr/superblock.h @@ -60,7 +60,7 @@ typedef struct hr_metadata { } hr_metadata_t; extern errno_t hr_write_meta_to_vol(hr_volume_t *); -extern errno_t hr_get_vol_from_meta(hr_config_t *, hr_volume_t *); +extern errno_t hr_fill_vol_from_meta(hr_volume_t *); #endif From e47a0324928f08206491a7cd32851c858958f64f Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 28 Oct 2024 21:02:39 +0100 Subject: [PATCH 043/324] hr: base for status handling --- uspace/app/hrctl/hrctl.c | 18 ++++++++++---- uspace/lib/device/include/hr.h | 17 ++++++++++++- uspace/lib/device/src/hr.c | 44 +++++++++++++++++++++++++++++----- uspace/srv/bd/hr/hr.c | 15 ++++++++++++ uspace/srv/bd/hr/superblock.c | 23 ++++++++++++------ uspace/srv/bd/hr/util.c | 33 ++++++++++++++++++++----- uspace/srv/bd/hr/util.h | 7 +++--- uspace/srv/bd/hr/var.h | 1 + 8 files changed, 131 insertions(+), 27 deletions(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index 8de8a5261a..8f2bcfb780 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -103,8 +103,13 @@ static errno_t fill_config_devs(int argc, char **argv, int optind, for (i = 0; i < cfg->dev_no; i++) { rc = loc_service_get_id(argv[optind], &cfg->devs[i], 0); - if (rc != EOK) { - printf("hrctl: error resolving device \"%s\"\n", argv[optind]); + if (rc == ENOENT) { + printf("hrctl: no device \"%s\", marking as missing\n", + argv[optind]); + cfg->devs[i] = 0; + } else if (rc != EOK) { + printf("hrctl: error resolving device \"%s\", aborting\n", + argv[optind]); return EINVAL; } @@ -189,8 +194,13 @@ static errno_t load_config(const char *path, hr_config_t *cfg) } rc = loc_service_get_id(extent_devname, &cfg->devs[i], 0); - if (rc != EOK) { - printf("hrctl: error resolving device \"%s\"\n", + if (rc == ENOENT) { + printf("hrctl: no device \"%s\", marking as missing\n", + extent_devname); + cfg->devs[i] = 0; + rc = EOK; + } else if (rc != EOK) { + printf("hrctl: error resolving device \"%s\", aborting\n", extent_devname); return EINVAL; } diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index 5ac9faa974..22c1814d5e 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -53,6 +53,17 @@ typedef enum hr_level { HR_LVL_UNKNOWN = 0xFF } hr_level_t; +typedef enum hr_vol_status { + HR_VOL_ONLINE, /* OK, OPTIMAL */ + HR_VOL_FAULTY +} hr_vol_status_t; + +typedef enum hr_ext_status { + HR_EXT_ONLINE, /* OK */ + HR_EXT_MISSING, + HR_EXT_FAILED +} hr_ext_status_t; + typedef struct hr { async_sess_t *sess; } hr_t; @@ -66,7 +77,7 @@ typedef struct hr_config { typedef struct hr_extent { service_id_t svc_id; - int status; + hr_ext_status_t status; } hr_extent_t; typedef struct hr_vol_info { @@ -77,6 +88,7 @@ typedef struct hr_vol_info { uint64_t nblocks; uint32_t strip_size; size_t bsize; + hr_vol_status_t status; } hr_vol_info_t; extern errno_t hr_sess_init(hr_t **); @@ -86,6 +98,9 @@ extern errno_t hr_create(hr_t *, hr_config_t *, bool); extern errno_t hr_stop(const char *); extern errno_t hr_print_status(void); +extern const char *hr_get_vol_status_msg(hr_vol_status_t); +extern const char *hr_get_ext_status_msg(hr_ext_status_t); + #endif /** @} diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index 1d4bc39c53..fff6eed111 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -129,6 +129,8 @@ static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info) return rc; printf("devname: %s\n", devname); + printf("status: %s\n", hr_get_vol_status_msg(vol_info->status)); + printf("level: %d\n", vol_info->level); if (vol_info->level == HR_LVL_0 || vol_info->level == HR_LVL_4) { if (vol_info->strip_size / 1024 < 1) @@ -149,15 +151,19 @@ static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info) printf("extents: [status] [index] [devname]\n"); for (i = 0; i < vol_info->extent_no; i++) { ext = &vol_info->extents[i]; - rc = loc_service_get_name(ext->svc_id, &devname); - if (rc != EOK) - return rc; + if (ext->status == HR_EXT_MISSING) { + devname = (char *) "MISSING-devname"; + } else { + rc = loc_service_get_name(ext->svc_id, &devname); + if (rc != EOK) + return rc; + } if (i == 0 && vol_info->level == HR_LVL_4) - printf(" P %d %zu %s\n", ext->status, i, devname); + printf(" P %s %zu %s\n", hr_get_ext_status_msg(ext->status), i, devname); else if (vol_info->level == HR_LVL_4) - printf(" %d %zu %s\n", ext->status, i, devname); + printf(" %s %zu %s\n", hr_get_ext_status_msg(ext->status), i, devname); else - printf(" %d %zu %s\n", ext->status, i, devname); + printf(" %s %zu %s\n", hr_get_ext_status_msg(ext->status), i, devname); } return EOK; } @@ -261,5 +267,31 @@ errno_t hr_print_status(void) return rc; } +const char *hr_get_vol_status_msg(hr_vol_status_t status) +{ + switch (status) { + case HR_VOL_ONLINE: + return "ONLINE"; + case HR_VOL_FAULTY: + return "FAULTY"; + default: + return "UNKNOWN"; + } +} + +const char *hr_get_ext_status_msg(hr_ext_status_t status) +{ + switch (status) { + case HR_EXT_ONLINE: + return "ONLINE"; + case HR_EXT_MISSING: + return "MISSING"; + case HR_EXT_FAILED: + return "FAILED"; + default: + return "UNKNOWN"; + } +} + /** @} */ diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 1e67b09d21..f42ef75662 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -133,6 +133,20 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) return; } + /* + * If there was a missing device provided + * for creation of a new array, abort + */ + if (!assemble) { + for (i = 0; i < cfg->dev_no; i++) { + if (cfg->devs[i] == 0) { + free(cfg); + async_answer_0(icall, EINVAL); + return; + } + } + } + new_volume = calloc(1, sizeof(hr_volume_t)); if (new_volume == NULL) { free(cfg); @@ -301,6 +315,7 @@ static void hr_print_status_srv(ipc_call_t *icall) info.nblocks = volume->data_blkno; info.strip_size = volume->strip_size; info.bsize = volume->bsize; + info.status = volume->status; if (!async_data_read_receive(&call, &size)) { rc = EREFUSED; diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index a661ec1797..eeded00c51 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -120,7 +120,6 @@ static errno_t validate_meta(hr_metadata_t *md) return EOK; } - errno_t hr_fill_vol_from_meta(hr_volume_t *vol) { log_msg(LOG_DEFAULT, LVL_NOTE, "hr_get_vol_from_meta()"); @@ -133,12 +132,18 @@ errno_t hr_fill_vol_from_meta(hr_volume_t *vol) return ENOMEM; service_id_t cfg_svc_id_order[HR_MAXDEVS] = { 0 }; - for (size_t i = 0; i < vol->dev_no; i++) + for (size_t i = 0; i < vol->dev_no; i++) { cfg_svc_id_order[i] = vol->extents[i].svc_id; + vol->extents[i].svc_id = 0; + vol->extents[i].status = HR_EXT_MISSING; + } - - uint32_t md_order[HR_MAXDEVS] = { 0 }; + int32_t md_order[HR_MAXDEVS] = { 0 }; for (size_t i = 0; i < vol->dev_no; i++) { + if (cfg_svc_id_order[i] == 0) { + md_order[i] = -1; + continue; + } rc = read_metadata(cfg_svc_id_order[i], metadata); if (rc != EOK) goto end; @@ -148,10 +153,14 @@ errno_t hr_fill_vol_from_meta(hr_volume_t *vol) md_order[i] = uint32_t_le2host(metadata->index); } - for (size_t i = 0; i < vol->dev_no; i++) - for (size_t j = 0; j < vol->dev_no; j++) - if (i == md_order[j]) + for (size_t i = 0; i < vol->dev_no; i++) { + for (size_t j = 0; j < vol->dev_no; j++) { + if (i == (uint32_t) md_order[j]) { vol->extents[i].svc_id = cfg_svc_id_order[j]; + vol->extents[i].status = HR_EXT_ONLINE; + } + } + } /* * still assume metadata are in sync across extents diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 4d0649679b..d01bd87f38 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -55,9 +55,15 @@ errno_t hr_init_devs(hr_volume_t *vol) size_t i; for (i = 0; i < vol->dev_no; i++) { + if (vol->extents[i].svc_id == 0) { + vol->extents[i].status = HR_EXT_MISSING; + continue; + } rc = block_init(vol->extents[i].svc_id); + vol->extents[i].status = HR_EXT_ONLINE; log_msg(LOG_DEFAULT, LVL_DEBUG, - "hr_init_devs(): initing (%" PRIun ")", vol->extents[i].svc_id); + "hr_init_devs(): initing (%" PRIun ")", + vol->extents[i].svc_id); if (rc != EOK) { log_msg(LOG_DEFAULT, LVL_ERROR, "hr_init_devs(): initing (%" PRIun ") failed, aborting", @@ -76,7 +82,8 @@ void hr_fini_devs(hr_volume_t *vol) size_t i; for (i = 0; i < vol->dev_no; i++) - block_fini(vol->extents[i].svc_id); + if (vol->extents[i].status != HR_EXT_MISSING) + block_fini(vol->extents[i].svc_id); } errno_t hr_register_volume(hr_volume_t *new_volume) @@ -126,15 +133,19 @@ errno_t hr_check_devs(hr_volume_t *vol, uint64_t *rblkno, size_t *rbsize) log_msg(LOG_DEFAULT, LVL_NOTE, "hr_check_devs()"); errno_t rc; - size_t i, bsize, last_bsize; - uint64_t nblocks, last_nblocks; + size_t i, bsize; + uint64_t nblocks; + size_t last_bsize = 0; + uint64_t last_nblocks = 0; uint64_t total_blocks = 0; for (i = 0; i < vol->dev_no; i++) { + if (vol->extents[i].status == HR_EXT_MISSING) + continue; rc = block_get_nblocks(vol->extents[i].svc_id, &nblocks); if (rc != EOK) goto error; - if (i != 0 && nblocks != last_nblocks) { + if (last_nblocks != 0 && nblocks != last_nblocks) { log_msg(LOG_DEFAULT, LVL_ERROR, "number of blocks differs"); rc = EINVAL; @@ -145,10 +156,12 @@ errno_t hr_check_devs(hr_volume_t *vol, uint64_t *rblkno, size_t *rbsize) } for (i = 0; i < vol->dev_no; i++) { + if (vol->extents[i].status == HR_EXT_MISSING) + continue; rc = block_get_bsize(vol->extents[i].svc_id, &bsize); if (rc != EOK) goto error; - if (i != 0 && bsize != last_bsize) { + if (last_bsize != 0 && bsize != last_bsize) { log_msg(LOG_DEFAULT, LVL_ERROR, "block sizes differ"); rc = EINVAL; goto error; @@ -176,5 +189,13 @@ void hr_add_ba_offset(hr_volume_t *vol, uint64_t *ba) *ba = *ba + vol->data_offset; } +void hr_update_ext_status(hr_volume_t *vol, uint64_t extent, hr_ext_status_t s) +{ + log_msg(LOG_DEFAULT, LVL_WARN, + "vol %s, changing extent: %lu, to status: %s", + vol->devname, extent, hr_get_ext_status_msg(s)); + vol->extents[extent].status = s; +} + /** @} */ diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index b2c68940e9..0c57fe6d5a 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -43,9 +43,10 @@ extern errno_t hr_init_devs(hr_volume_t *); extern void hr_fini_devs(hr_volume_t *); extern errno_t hr_register_volume(hr_volume_t *); -errno_t hr_check_devs(hr_volume_t *, uint64_t *, size_t *); -errno_t hr_check_ba_range(hr_volume_t *, size_t, uint64_t); -void hr_add_ba_offset(hr_volume_t *, uint64_t *); +extern errno_t hr_check_devs(hr_volume_t *, uint64_t *, size_t *); +extern errno_t hr_check_ba_range(hr_volume_t *, size_t, uint64_t); +extern void hr_add_ba_offset(hr_volume_t *, uint64_t *); +extern void hr_update_ext_status(hr_volume_t *, uint64_t, hr_ext_status_t); #endif diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index 264909b98a..00d4a96e2d 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -66,6 +66,7 @@ typedef struct hr_volume { size_t bsize; size_t dev_no; hr_level_t level; + hr_vol_status_t status; } hr_volume_t; typedef enum { From 9fc1d36d16e562fc783d941c4e1a18dde2509e14 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 28 Oct 2024 21:03:53 +0100 Subject: [PATCH 044/324] hr: RAID 0 status handling --- uspace/srv/bd/hr/raid0.c | 49 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index 006a82c5af..2604ec2753 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -73,6 +73,34 @@ static bd_ops_t hr_raid0_bd_ops = { .get_num_blocks = hr_raid0_bd_get_num_blocks }; +static errno_t hr_raid0_check_vol_status(hr_volume_t *vol) +{ + if (vol->status == HR_VOL_ONLINE) + return EOK; + return EINVAL; +} + +/* + * Update vol->status and return EOK if volume + * is usable + */ +static errno_t hr_raid0_update_vol_status(hr_volume_t *vol) +{ + for (size_t i = 0; i < vol->dev_no; i++) { + if (vol->extents[i].status != HR_EXT_ONLINE) { + log_msg(LOG_DEFAULT, LVL_ERROR, + "RAID 0 needs all disks to be ONLINE, marking " + "\"%s\" (%lu) as FAULTY", + vol->devname, vol->svc_id); + vol->status = HR_VOL_FAULTY; + return EINVAL; + } + } + + vol->status = HR_VOL_ONLINE; + return EOK; +} + static errno_t hr_raid0_bd_open(bd_srvs_t *bds, bd_srv_t *bd) { log_msg(LOG_DEFAULT, LVL_NOTE, "hr_bd_open()"); @@ -109,6 +137,12 @@ static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, fibril_mutex_lock(&vol->lock); + rc = hr_raid0_check_vol_status(vol); + if (rc != EOK) { + fibril_mutex_unlock(&vol->lock); + return EIO; + } + left = cnt; while (left != 0) { phys_block = ext_stripe * strip_size + strip_off; @@ -134,8 +168,16 @@ static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, default: rc = EINVAL; } - if (rc != EOK) + + if (rc == ENOENT) { + hr_update_ext_status(vol, extent, HR_EXT_MISSING); + rc = EIO; goto error; + } else if (rc != EOK) { + hr_update_ext_status(vol, extent, HR_EXT_FAILED); + rc = EIO; + goto error; + } left -= cnt; strip_off = 0; @@ -147,6 +189,7 @@ static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, } error: + (void) hr_raid0_update_vol_status(vol); fibril_mutex_unlock(&vol->lock); return rc; } @@ -196,6 +239,10 @@ errno_t hr_raid0_create(hr_volume_t *new_volume) return EINVAL; } + rc = hr_raid0_update_vol_status(new_volume); + if (rc != EOK) + return rc; + bd_srvs_init(&new_volume->hr_bds); new_volume->hr_bds.ops = &hr_raid0_bd_ops; new_volume->hr_bds.sarg = new_volume; From 1903d7769934b8a6da9b8cf9e436f445a74c8b6e Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 28 Oct 2024 21:05:29 +0100 Subject: [PATCH 045/324] bdwrite: fill blocks with 'A' - 'Z' Following parity blocks in hexdump is easier. --- uspace/app/bdwrite/bdwrite.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/uspace/app/bdwrite/bdwrite.c b/uspace/app/bdwrite/bdwrite.c index 82cea328a2..1d4e2947c9 100644 --- a/uspace/app/bdwrite/bdwrite.c +++ b/uspace/app/bdwrite/bdwrite.c @@ -117,7 +117,10 @@ int main(int argc, char **argv) uint64_t blks_to_write = min(to_alloc / bsize, left); uint8_t *ptr = buf; for (size_t i = 0; i < blks_to_write; i++) { + /* memset(ptr, (i + 1) % 0x100, bsize); + */ + memset(ptr, 'A' + (i % 26), bsize); ptr = (uint8_t *)((uintptr_t) ptr + bsize); } rc = block_write_direct(dev, off, blks_to_write, buf); From a438de5b97f5c64395e8f079ee59e3d2f94909b6 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 28 Oct 2024 22:00:19 +0100 Subject: [PATCH 046/324] hr: be consistent with extent terminology --- uspace/srv/bd/hr/raid0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index 2604ec2753..580f4921f7 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -89,7 +89,7 @@ static errno_t hr_raid0_update_vol_status(hr_volume_t *vol) for (size_t i = 0; i < vol->dev_no; i++) { if (vol->extents[i].status != HR_EXT_ONLINE) { log_msg(LOG_DEFAULT, LVL_ERROR, - "RAID 0 needs all disks to be ONLINE, marking " + "RAID 0 needs all extents to be ONLINE, marking " "\"%s\" (%lu) as FAULTY", vol->devname, vol->svc_id); vol->status = HR_VOL_FAULTY; From 6124ee1520304f778039d7422108bb55b56b921c Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 28 Oct 2024 22:30:26 +0100 Subject: [PATCH 047/324] bdwrite: cstyle --- uspace/app/bdwrite/bdwrite.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/uspace/app/bdwrite/bdwrite.c b/uspace/app/bdwrite/bdwrite.c index 1d4e2947c9..7c1821e378 100644 --- a/uspace/app/bdwrite/bdwrite.c +++ b/uspace/app/bdwrite/bdwrite.c @@ -117,9 +117,7 @@ int main(int argc, char **argv) uint64_t blks_to_write = min(to_alloc / bsize, left); uint8_t *ptr = buf; for (size_t i = 0; i < blks_to_write; i++) { - /* - memset(ptr, (i + 1) % 0x100, bsize); - */ + /* memset(ptr, (i + 1) % 0x100, bsize); */ memset(ptr, 'A' + (i % 26), bsize); ptr = (uint8_t *)((uintptr_t) ptr + bsize); } From d84773ac35e32d33b7b0368f165b6660ba6a1e0d Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 28 Oct 2024 22:46:47 +0100 Subject: [PATCH 048/324] hr: RAID 1 state handling --- uspace/lib/device/include/hr.h | 3 +- uspace/lib/device/src/hr.c | 2 + uspace/srv/bd/hr/raid1.c | 96 ++++++++++++++++++++++++++++++++-- 3 files changed, 96 insertions(+), 5 deletions(-) diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index 22c1814d5e..f3b9eff7d2 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -55,7 +55,8 @@ typedef enum hr_level { typedef enum hr_vol_status { HR_VOL_ONLINE, /* OK, OPTIMAL */ - HR_VOL_FAULTY + HR_VOL_FAULTY, + HR_VOL_WEAKENED /* used for partial, but usable mirror */ } hr_vol_status_t; typedef enum hr_ext_status { diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index fff6eed111..f5ec079482 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -274,6 +274,8 @@ const char *hr_get_vol_status_msg(hr_vol_status_t status) return "ONLINE"; case HR_VOL_FAULTY: return "FAULTY"; + case HR_VOL_WEAKENED: + return "WEAKENED"; default: return "UNKNOWN"; } diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 60cf6a7826..5f55752132 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -72,6 +72,57 @@ static bd_ops_t hr_raid1_bd_ops = { .get_num_blocks = hr_raid1_bd_get_num_blocks }; +static errno_t hr_raid1_check_vol_status(hr_volume_t *vol) +{ + if (vol->status == HR_VOL_ONLINE || + vol->status == HR_VOL_WEAKENED) + return EOK; + return EINVAL; +} + +/* + * Update vol->status and return EOK if volume + * is usable + */ +static errno_t hr_raid1_update_vol_status(hr_volume_t *vol) +{ + hr_vol_status_t old_state = vol->status; + size_t healthy = 0; + for (size_t i = 0; i < vol->dev_no; i++) + if (vol->extents[i].status == HR_EXT_ONLINE) + healthy++; + + if (healthy == 0) { + if (old_state != HR_VOL_FAULTY) { + log_msg(LOG_DEFAULT, LVL_ERROR, + "RAID 1 needs at least 1 extent to be ONLINE, " + "marking \"%s\" (%lu) as FAULTY", + vol->devname, vol->svc_id); + vol->status = HR_VOL_FAULTY; + } + return EINVAL; + } else if (healthy < vol->dev_no) { + if (old_state != HR_VOL_WEAKENED) { + log_msg(LOG_DEFAULT, LVL_ERROR, + "RAID 1 array \"%s\" (%lu) has some inactive " + "extents, marking as WEAKENED", + vol->devname, vol->svc_id); + vol->status = HR_VOL_WEAKENED; + } + return EOK; + } else { + if (old_state != HR_VOL_ONLINE) { + log_msg(LOG_DEFAULT, LVL_ERROR, + "RAID 1 array \"%s\" (%lu) has all extents active, " + "marking as ONLINE", + vol->devname, vol->svc_id); + vol->status = HR_VOL_ONLINE; + } + return EOK; + } + +} + static errno_t hr_raid1_bd_open(bd_srvs_t *bds, bd_srv_t *bd) { log_msg(LOG_DEFAULT, LVL_NOTE, "hr_bd_open()"); @@ -84,6 +135,15 @@ static errno_t hr_raid1_bd_close(bd_srv_t *bd) return EOK; } +static void handle_extent_error(hr_volume_t *vol, size_t extent, + errno_t rc) +{ + if (rc == ENOENT) + hr_update_ext_status(vol, extent, HR_EXT_MISSING); + else if (rc != EOK) + hr_update_ext_status(vol, extent, HR_EXT_FAILED); +} + static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, size_t cnt, void *data_read, const void *data_write, size_t size) { @@ -103,35 +163,59 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, fibril_mutex_lock(&vol->lock); + rc = hr_raid1_check_vol_status(vol); + if (rc != EOK) { + fibril_mutex_unlock(&vol->lock); + return EIO; + } + + size_t successful = 0; switch (type) { case HR_BD_SYNC: for (i = 0; i < vol->dev_no; i++) { + if (vol->extents[i].status != HR_EXT_ONLINE) + continue; rc = block_sync_cache(vol->extents[i].svc_id, ba, cnt); if (rc != EOK) - goto error; + handle_extent_error(vol, i, rc); + else + successful++; } break; case HR_BD_READ: for (i = 0; i < vol->dev_no; i++) { + if (vol->extents[i].status != HR_EXT_ONLINE) + continue; rc = block_read_direct(vol->extents[i].svc_id, ba, cnt, data_read); if (rc != EOK) - goto error; + handle_extent_error(vol, i, rc); + else + successful++; } break; case HR_BD_WRITE: for (i = 0; i < vol->dev_no; i++) { + if (vol->extents[i].status != HR_EXT_ONLINE) + continue; rc = block_write_direct(vol->extents[i].svc_id, ba, cnt, data_write); if (rc != EOK) - goto error; + handle_extent_error(vol, i, rc); + else + successful++; } break; default: rc = EINVAL; } -error: + if (successful > 0) + rc = EOK; + else + rc = EIO; + + (void) hr_raid1_update_vol_status(vol); fibril_mutex_unlock(&vol->lock); return rc; } @@ -181,6 +265,10 @@ errno_t hr_raid1_create(hr_volume_t *new_volume) return EINVAL; } + rc = hr_raid1_update_vol_status(new_volume); + if (rc != EOK) + return rc; + bd_srvs_init(&new_volume->hr_bds); new_volume->hr_bds.ops = &hr_raid1_bd_ops; new_volume->hr_bds.sarg = new_volume; From cf28ffd3efdce6cee71cacbd1154fa35c8baa679 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 28 Oct 2024 23:19:45 +0100 Subject: [PATCH 049/324] hr: add option to silently fail an extent --- uspace/app/hrctl/hrctl.c | 10 ++++++++-- uspace/lib/device/include/hr.h | 2 +- uspace/lib/device/src/hr.c | 4 ++-- uspace/srv/bd/hr/hr.c | 23 +++++++++++++++-------- 4 files changed, 26 insertions(+), 13 deletions(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index 8f2bcfb780..5c2b6d8f44 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -58,6 +58,7 @@ static const char usage_str[] = " -A, --assemble-file=PATH create an array from file\n" " -s, --status display status of active arrays\n" " -T, --stop stop an active array\n" + " -F, --fail-extent fail an extent, use with -T and set it before\n" " -c, --create=NAME create new array\n" " -a, --assemble=NAME assemble an existing array\n" " -n non-zero number of devices\n" @@ -87,6 +88,7 @@ static struct option const long_options[] = { { "create-file", required_argument, 0, 'C' }, { "assemble-file", required_argument, 0, 'A' }, { "stop", required_argument, 0, 'T' }, + { "fail-extent", required_argument, 0, 'F' }, { 0, 0, 0, 0 } }; @@ -219,6 +221,7 @@ int main(int argc, char **argv) errno_t rc; int retval, c; bool create, assemble; + long fail_extent = -1; hr_t *hr; hr_config_t *cfg; @@ -240,7 +243,7 @@ int main(int argc, char **argv) optind = 0; while (c != -1) { - c = getopt_long(argc, argv, "hsC:c:A:a:l:0145Ln:T:", + c = getopt_long(argc, argv, "hsC:c:A:a:l:0145Ln:T:F:", long_options, NULL); switch (c) { case 'h': @@ -285,7 +288,7 @@ int main(int argc, char **argv) assemble = true; break; case 'T': - rc = hr_stop(optarg); + rc = hr_stop(optarg, fail_extent); free(cfg); if (rc != EOK) { if (rc == ENOENT) @@ -294,6 +297,9 @@ int main(int argc, char **argv) return 1; } return 0; + case 'F': + fail_extent = strtol(optarg, NULL, 10); + break; case 'l': if (cfg->level != HR_LVL_UNKNOWN) goto bad; diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index f3b9eff7d2..780b2cdf11 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -96,7 +96,7 @@ extern errno_t hr_sess_init(hr_t **); extern void hr_sess_destroy(hr_t *); extern errno_t hr_create(hr_t *, hr_config_t *, bool); -extern errno_t hr_stop(const char *); +extern errno_t hr_stop(const char *, long); extern errno_t hr_print_status(void); extern const char *hr_get_vol_status_msg(hr_vol_status_t); diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index f5ec079482..909ec03daa 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -168,7 +168,7 @@ static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info) return EOK; } -errno_t hr_stop(const char *devname) +errno_t hr_stop(const char *devname, long extent) { hr_t *hr; errno_t rc; @@ -188,7 +188,7 @@ errno_t hr_stop(const char *devname) rc = EINVAL; goto error; } - rc = async_req_1_0(exch, HR_STOP, svc_id); + rc = async_req_2_0(exch, HR_STOP, svc_id, extent); async_exchange_end(exch); if (rc != EOK) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index f42ef75662..1fea425716 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -254,11 +254,13 @@ static void hr_stop_srv(ipc_call_t *icall) { log_msg(LOG_DEFAULT, LVL_NOTE, "hr_stop_srv()"); - errno_t rc; + errno_t rc = EOK; service_id_t svc_id; + long fail_extent; hr_volume_t *vol; svc_id = ipc_get_arg1(icall); + fail_extent = (long) ipc_get_arg2(icall); vol = hr_get_volume(svc_id); if (vol == NULL) { @@ -266,14 +268,19 @@ static void hr_stop_srv(ipc_call_t *icall) return; } - rc = hr_remove_volume(svc_id); - if (rc != EOK) { - async_answer_0(icall, rc); - return; + if (fail_extent == -1) { + rc = hr_remove_volume(svc_id); + if (rc != EOK) { + async_answer_0(icall, rc); + return; + } + rc = loc_service_unregister(hr_srv, svc_id); + } else { + /* fibril safe for now */ + fibril_mutex_lock(&vol->lock); + hr_update_ext_status(vol, fail_extent, HR_EXT_FAILED); + fibril_mutex_unlock(&vol->lock); } - - rc = loc_service_unregister(hr_srv, svc_id); - async_answer_0(icall, rc); } From 1cfa1623d91869bcfdf53675e257bf82b8522f47 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 4 Nov 2024 18:05:27 +0100 Subject: [PATCH 050/324] hr: assert block size to be a multiple of 512 --- uspace/srv/bd/hr/util.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index d01bd87f38..cb00e0493c 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -169,6 +169,12 @@ errno_t hr_check_devs(hr_volume_t *vol, uint64_t *rblkno, size_t *rbsize) last_bsize = bsize; } + if ((bsize % 512) != 0) { + log_msg(LOG_DEFAULT, LVL_ERROR, + "block size not multiple of 512"); + return EINVAL; + } + if (rblkno != NULL) *rblkno = total_blocks; if (rbsize != NULL) From 52af125505eeee81994e135d03a51857b0352157 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 8 Nov 2024 16:08:30 +0100 Subject: [PATCH 051/324] hr: add hr_sync_all_extents() --- uspace/srv/bd/hr/util.c | 26 ++++++++++++++++++++++++++ uspace/srv/bd/hr/util.h | 1 + 2 files changed, 27 insertions(+) diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index cb00e0493c..9787afce85 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -203,5 +203,31 @@ void hr_update_ext_status(hr_volume_t *vol, uint64_t extent, hr_ext_status_t s) vol->extents[extent].status = s; } +/* + * Do a whole sync (ba = 0, cnt = 0) across all extents, + * and update extent status. *For now*, the caller has to + * update volume status after the syncs. + * + * TODO: add update_vol_status fcn ptr for each raid + */ +void hr_sync_all_extents(hr_volume_t *vol) +{ + errno_t rc; + + fibril_mutex_lock(&vol->lock); + for (size_t i = 0; i < vol->dev_no; i++) { + if (vol->extents[i].status != HR_EXT_ONLINE) + continue; + rc = block_sync_cache(vol->extents[i].svc_id, 0, 0); + if (rc != EOK && rc != ENOTSUP) { + if (rc == ENOENT) + hr_update_ext_status(vol, i, HR_EXT_MISSING); + else if (rc != EOK) + hr_update_ext_status(vol, i, HR_EXT_FAILED); + } + } + fibril_mutex_unlock(&vol->lock); +} + /** @} */ diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index 0c57fe6d5a..9834e070c1 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -47,6 +47,7 @@ extern errno_t hr_check_devs(hr_volume_t *, uint64_t *, size_t *); extern errno_t hr_check_ba_range(hr_volume_t *, size_t, uint64_t); extern void hr_add_ba_offset(hr_volume_t *, uint64_t *); extern void hr_update_ext_status(hr_volume_t *, uint64_t, hr_ext_status_t); +extern void hr_sync_all_extents(hr_volume_t *); #endif From 5f543e9186ef3f5ceb3c24f016bc226aaa9fe496 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 8 Nov 2024 16:12:50 +0100 Subject: [PATCH 052/324] hr: RAID0: propagate sync --- uspace/srv/bd/hr/raid0.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index 580f4921f7..1cb59255ea 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -121,6 +121,13 @@ static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, uint64_t phys_block; size_t left; + /* propagate sync */ + if (type == HR_BD_SYNC && ba == 0 && cnt == 0) { + hr_sync_all_extents(vol); + rc = hr_raid0_update_vol_status(vol); + return rc; + } + if (type == HR_BD_READ || type == HR_BD_WRITE) if (size < cnt * vol->bsize) return EINVAL; From 182ffcc2cc90bf2094406e6305862139066c8519 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 8 Nov 2024 16:13:36 +0100 Subject: [PATCH 053/324] hr: allow unsupported sync in RAID 0,1 --- uspace/srv/bd/hr/raid0.c | 3 +++ uspace/srv/bd/hr/raid1.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index 1cb59255ea..95d4c3d619 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -159,6 +159,9 @@ static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, case HR_BD_SYNC: rc = block_sync_cache(vol->extents[extent].svc_id, phys_block, cnt); + /* allow unsupported sync */ + if (rc == ENOTSUP) + rc = EOK; break; case HR_BD_READ: rc = block_read_direct(vol->extents[extent].svc_id, diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 5f55752132..bf7755a00e 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -176,7 +176,7 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, if (vol->extents[i].status != HR_EXT_ONLINE) continue; rc = block_sync_cache(vol->extents[i].svc_id, ba, cnt); - if (rc != EOK) + if (rc != EOK && rc != ENOTSUP) handle_extent_error(vol, i, rc); else successful++; From 13ce5522e428fb535cfdaf8793d7663311a175eb Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 10 Nov 2024 17:11:36 +0100 Subject: [PATCH 054/324] hr: add DEGRADED volume state Use it for weakened mirror as well. --- uspace/lib/device/include/hr.h | 2 +- uspace/lib/device/src/hr.c | 4 ++-- uspace/srv/bd/hr/raid1.c | 9 ++++----- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index 780b2cdf11..264d98e683 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -56,7 +56,7 @@ typedef enum hr_level { typedef enum hr_vol_status { HR_VOL_ONLINE, /* OK, OPTIMAL */ HR_VOL_FAULTY, - HR_VOL_WEAKENED /* used for partial, but usable mirror */ + HR_VOL_DEGRADED /* also used for partial, but usable mirror */ } hr_vol_status_t; typedef enum hr_ext_status { diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index 909ec03daa..abc6c799b3 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -274,8 +274,8 @@ const char *hr_get_vol_status_msg(hr_vol_status_t status) return "ONLINE"; case HR_VOL_FAULTY: return "FAULTY"; - case HR_VOL_WEAKENED: - return "WEAKENED"; + case HR_VOL_DEGRADED: + return "DEGRADED"; default: return "UNKNOWN"; } diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index bf7755a00e..771017ab88 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -75,7 +75,7 @@ static bd_ops_t hr_raid1_bd_ops = { static errno_t hr_raid1_check_vol_status(hr_volume_t *vol) { if (vol->status == HR_VOL_ONLINE || - vol->status == HR_VOL_WEAKENED) + vol->status == HR_VOL_DEGRADED) return EOK; return EINVAL; } @@ -102,12 +102,12 @@ static errno_t hr_raid1_update_vol_status(hr_volume_t *vol) } return EINVAL; } else if (healthy < vol->dev_no) { - if (old_state != HR_VOL_WEAKENED) { + if (old_state != HR_VOL_DEGRADED) { log_msg(LOG_DEFAULT, LVL_ERROR, "RAID 1 array \"%s\" (%lu) has some inactive " - "extents, marking as WEAKENED", + "extents, marking as DEGRADED", vol->devname, vol->svc_id); - vol->status = HR_VOL_WEAKENED; + vol->status = HR_VOL_DEGRADED; } return EOK; } else { @@ -120,7 +120,6 @@ static errno_t hr_raid1_update_vol_status(hr_volume_t *vol) } return EOK; } - } static errno_t hr_raid1_bd_open(bd_srvs_t *bds, bd_srv_t *bd) From 11111e4dfde463f8ab7ecab4ccb269cc49d1babc Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 10 Nov 2024 22:29:06 +0100 Subject: [PATCH 055/324] hr: add states to RAID4, and degraded R/W --- uspace/srv/bd/hr/raid4.c | 283 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 266 insertions(+), 17 deletions(-) diff --git a/uspace/srv/bd/hr/raid4.c b/uspace/srv/bd/hr/raid4.c index fcf1489319..62d9d4d0d2 100644 --- a/uspace/srv/bd/hr/raid4.c +++ b/uspace/srv/bd/hr/raid4.c @@ -64,6 +64,9 @@ static errno_t hr_raid4_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, static errno_t hr_raid4_bd_get_block_size(bd_srv_t *, size_t *); static errno_t hr_raid4_bd_get_num_blocks(bd_srv_t *, aoff64_t *); +static errno_t hr_raid4_write_parity(hr_volume_t *, uint64_t, uint64_t, + const void *, size_t); + static bd_ops_t hr_raid4_bd_ops = { .open = hr_raid4_bd_open, .close = hr_raid4_bd_close, @@ -74,6 +77,64 @@ static bd_ops_t hr_raid4_bd_ops = { .get_num_blocks = hr_raid4_bd_get_num_blocks }; +static errno_t hr_raid4_vol_usable(hr_volume_t *vol) +{ + if (vol->status == HR_VOL_ONLINE || + vol->status == HR_VOL_DEGRADED) + return EOK; + return EINVAL; +} + +/* + * Return first bad extent + */ +static ssize_t hr_raid4_get_bad_ext(hr_volume_t *vol) +{ + for (size_t i = 0; i < vol->dev_no; i++) + if (vol->extents[i].status != HR_EXT_ONLINE) + return i; + return -1; +} + +static errno_t hr_raid4_update_vol_status(hr_volume_t *vol) +{ + hr_vol_status_t old_state = vol->status; + size_t bad = 0; + for (size_t i = 0; i < vol->dev_no; i++) + if (vol->extents[i].status != HR_EXT_ONLINE) + bad++; + + switch (bad) { + case 0: + if (old_state != HR_VOL_ONLINE) { + log_msg(LOG_DEFAULT, LVL_ERROR, + "RAID 4 has all extents online, " + "marking \"%s\" (%lu) as ONLINE", + vol->devname, vol->svc_id); + vol->status = HR_VOL_ONLINE; + } + return EOK; + case 1: + if (old_state != HR_VOL_DEGRADED) { + log_msg(LOG_DEFAULT, LVL_ERROR, + "RAID 4 array \"%s\" (%lu) has 1 extent inactive, " + "marking as DEGRADED", + vol->devname, vol->svc_id); + vol->status = HR_VOL_DEGRADED; + } + return EOK; + default: + if (old_state != HR_VOL_FAULTY) { + log_msg(LOG_DEFAULT, LVL_ERROR, + "RAID 4 array \"%s\" (%lu) has more than one 1 " + "extent inactive, marking as FAULTY", + vol->devname, vol->svc_id); + vol->status = HR_VOL_FAULTY; + } + return EINVAL; + } +} + static void xor(void *dst, const void *src, size_t size) { size_t i; @@ -84,7 +145,49 @@ static void xor(void *dst, const void *src, size_t size) *d++ ^= *s++; } -static errno_t write_parity(hr_volume_t *vol, uint64_t extent, uint64_t block, +static errno_t hr_raid4_read_degraded(hr_volume_t *vol, uint64_t bad, + uint64_t block, void *data, size_t cnt) +{ + errno_t rc; + size_t i, j; + void *xorbuf; + void *buf; + + xorbuf = malloc(vol->bsize); + if (xorbuf == NULL) + return ENOMEM; + + buf = malloc(vol->bsize); + if (buf == NULL) { + free(xorbuf); + return ENOMEM; + } + + /* read all other extents in stripe */ + for (j = 0; j < cnt; j++) { + memset(xorbuf, 0, vol->bsize); + for (i = 0; i < vol->dev_no; i++) { + if (i == bad) { + continue; + } else { + rc = block_read_direct(vol->extents[i].svc_id, + block, 1, buf); + if (rc != EOK) + goto end; + xor(xorbuf, buf, vol->bsize); + } + } + memcpy(data, xorbuf, vol->bsize); + data = (void *) ((uintptr_t) data + vol->bsize); + block++; + } +end: + free(xorbuf); + free(buf); + return rc; +} + +static errno_t hr_raid4_write(hr_volume_t *vol, uint64_t extent, aoff64_t ba, const void *data, size_t cnt) { errno_t rc; @@ -92,6 +195,104 @@ static errno_t write_parity(hr_volume_t *vol, uint64_t extent, uint64_t block, void *xorbuf; void *buf; + ssize_t bad = hr_raid4_get_bad_ext(vol); + if (bad < 1) { + rc = block_write_direct(vol->extents[extent].svc_id, ba, cnt, + data); + if (rc != EOK) + return rc; + /* + * DEGRADED parity - skip parity write + */ + if (bad == 0) + return EOK; + + rc = hr_raid4_write_parity(vol, extent, ba, data, cnt); + return rc; + } + + xorbuf = malloc(vol->bsize); + if (xorbuf == NULL) + return ENOMEM; + + buf = malloc(vol->bsize); + if (buf == NULL) { + free(xorbuf); + return ENOMEM; + } + + if (extent == (size_t) bad) { + /* + * new parity = read other and xor in new data + * + * write new parity + */ + for (j = 0; j < cnt; j++) { + memset(xorbuf, 0, vol->bsize); + for (i = 1; i < vol->dev_no; i++) { + if (i == (size_t) bad) { + continue; + } else { + rc = block_read_direct(vol->extents[i].svc_id, + ba, 1, buf); + if (rc != EOK) + goto end; + xor(xorbuf, buf, vol->bsize); + } + } + xor(xorbuf, data, vol->bsize); + rc = block_write_direct(vol->extents[0].svc_id, ba, 1, + xorbuf); + if (rc != EOK) + goto end; + data = (void *) ((uintptr_t) data + vol->bsize); + ba++; + } + } else { + /* + * new parity = xor original data and old parity and new data + * + * write parity, new data + */ + for (j = 0; j < cnt; j++) { + rc = block_read_direct(vol->extents[extent].svc_id, ba, + 1, xorbuf); + if (rc != EOK) + goto end; + rc = block_read_direct(vol->extents[0].svc_id, ba, 1, + buf); + if (rc != EOK) + goto end; + xor(xorbuf, buf, vol->bsize); + + xor(xorbuf, data, vol->bsize); + + rc = block_write_direct(vol->extents[0].svc_id, ba, 1, + xorbuf); + if (rc != EOK) + goto end; + rc = block_write_direct(vol->extents[extent].svc_id, + ba, 1, data); + if (rc != EOK) + goto end; + data = (void *) ((uintptr_t) data + vol->bsize); + ba++; + } + } +end: + free(xorbuf); + free(buf); + return rc; +} + +static errno_t hr_raid4_write_parity(hr_volume_t *vol, uint64_t extent, + uint64_t block, const void *data, size_t cnt) +{ + errno_t rc; + size_t i, j; + void *xorbuf; + void *buf; + xorbuf = malloc(vol->bsize); if (xorbuf == NULL) return ENOMEM; @@ -148,6 +349,13 @@ static errno_t hr_raid4_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, uint64_t phys_block; size_t left; + /* propagate sync */ + if (type == HR_BD_SYNC && ba == 0 && cnt == 0) { + hr_sync_all_extents(vol); + rc = hr_raid4_update_vol_status(vol); + return rc; + } + if (type == HR_BD_READ || type == HR_BD_WRITE) if (size < cnt * vol->bsize) return EINVAL; @@ -164,6 +372,12 @@ static errno_t hr_raid4_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, fibril_mutex_lock(&vol->lock); + rc = hr_raid4_vol_usable(vol); + if (rc != EOK) { + fibril_mutex_unlock(&vol->lock); + return EIO; + } + left = cnt; while (left != 0) { phys_block = ext_stripe * strip_size + strip_off; @@ -171,33 +385,63 @@ static errno_t hr_raid4_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, hr_add_ba_offset(vol, &phys_block); switch (type) { case HR_BD_SYNC: + if (vol->extents[extent].status != HR_EXT_ONLINE) + break; rc = block_sync_cache(vol->extents[extent].svc_id, phys_block, cnt); + /* allow unsupported sync */ + if (rc == ENOTSUP) + rc = EOK; break; case HR_BD_READ: - rc = block_read_direct(vol->extents[extent].svc_id, - phys_block, cnt, data_read); - data_read = (void *) ((uintptr_t) data_read + - (vol->bsize * cnt)); + retry_read: + ssize_t bad = hr_raid4_get_bad_ext(vol); + if (bad > 0 && extent == (size_t) bad) { + rc = hr_raid4_read_degraded(vol, bad, + phys_block, data_read, cnt); + } else { + rc = block_read_direct(vol->extents[extent].svc_id, + phys_block, cnt, data_read); + } + + data_read += vol->bsize * cnt; break; case HR_BD_WRITE: - rc = block_write_direct(vol->extents[extent].svc_id, - phys_block, cnt, data_write); - if (rc != EOK) - goto error; - rc = write_parity(vol, extent, phys_block, data_write, - cnt); - if (rc != EOK) - goto error; - data_write = (void *) ((uintptr_t) data_write + - (vol->bsize * cnt)); + retry_write: + rc = hr_raid4_write(vol, extent, phys_block, + data_write, cnt); + + data_write += vol->bsize * cnt; break; default: rc = EINVAL; + goto error; } - if (rc != EOK) - goto error; + if (rc == ENOENT) + hr_update_ext_status(vol, extent, HR_EXT_MISSING); + else if (rc != EOK) + hr_update_ext_status(vol, extent, HR_EXT_FAILED); + + if (rc != EOK) { + rc = hr_raid4_update_vol_status(vol); + if (rc == EOK) { + /* + * State changed from ONLINE -> DEGRADED, + * rewind and retry + */ + if (type == HR_BD_WRITE) { + data_write -= vol->bsize * cnt; + goto retry_write; + } else if (type == HR_BD_WRITE) { + data_read -= vol->bsize * cnt; + goto retry_read; + } + } else { + rc = EIO; + goto error; + } + } left -= cnt; strip_off = 0; @@ -209,6 +453,7 @@ static errno_t hr_raid4_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, } error: + (void) hr_raid4_update_vol_status(vol); fibril_mutex_unlock(&vol->lock); return rc; } @@ -258,6 +503,10 @@ errno_t hr_raid4_create(hr_volume_t *new_volume) return EINVAL; } + rc = hr_raid4_update_vol_status(new_volume); + if (rc != EOK) + return rc; + bd_srvs_init(&new_volume->hr_bds); new_volume->hr_bds.ops = &hr_raid4_bd_ops; new_volume->hr_bds.sarg = new_volume; From 90eec9c053f43826a68930ff649f79c2b1d608c8 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 10 Nov 2024 22:34:49 +0100 Subject: [PATCH 056/324] hr: allocate xorbuf with whole request length As it can be 64K at most at the moment, we can allocate whole request size. --- uspace/srv/bd/hr/raid4.c | 162 +++++++++++++++++++-------------------- 1 file changed, 77 insertions(+), 85 deletions(-) diff --git a/uspace/srv/bd/hr/raid4.c b/uspace/srv/bd/hr/raid4.c index 62d9d4d0d2..09819e3bc9 100644 --- a/uspace/srv/bd/hr/raid4.c +++ b/uspace/srv/bd/hr/raid4.c @@ -86,7 +86,8 @@ static errno_t hr_raid4_vol_usable(hr_volume_t *vol) } /* - * Return first bad extent + * Returns (-1) if all extents are online, + * else returns index of first bad one. */ static ssize_t hr_raid4_get_bad_ext(hr_volume_t *vol) { @@ -149,38 +150,36 @@ static errno_t hr_raid4_read_degraded(hr_volume_t *vol, uint64_t bad, uint64_t block, void *data, size_t cnt) { errno_t rc; - size_t i, j; + size_t i; void *xorbuf; void *buf; + uint64_t len = vol->bsize * cnt; - xorbuf = malloc(vol->bsize); + xorbuf = malloc(len); if (xorbuf == NULL) return ENOMEM; - buf = malloc(vol->bsize); + buf = malloc(len); if (buf == NULL) { free(xorbuf); return ENOMEM; } - /* read all other extents in stripe */ - for (j = 0; j < cnt; j++) { - memset(xorbuf, 0, vol->bsize); - for (i = 0; i < vol->dev_no; i++) { - if (i == bad) { - continue; - } else { - rc = block_read_direct(vol->extents[i].svc_id, - block, 1, buf); - if (rc != EOK) - goto end; - xor(xorbuf, buf, vol->bsize); - } + /* read all other extents in the stripe */ + memset(xorbuf, 0, len); + for (i = 0; i < vol->dev_no; i++) { + if (i == bad) { + continue; + } else { + rc = block_read_direct(vol->extents[i].svc_id, block, + cnt, buf); + if (rc != EOK) + goto end; + xor(xorbuf, buf, len); } - memcpy(data, xorbuf, vol->bsize); - data = (void *) ((uintptr_t) data + vol->bsize); - block++; } + + memcpy(data, xorbuf, len); end: free(xorbuf); free(buf); @@ -191,9 +190,10 @@ static errno_t hr_raid4_write(hr_volume_t *vol, uint64_t extent, aoff64_t ba, const void *data, size_t cnt) { errno_t rc; - size_t i, j; + size_t i; void *xorbuf; void *buf; + uint64_t len = vol->bsize * cnt; ssize_t bad = hr_raid4_get_bad_ext(vol); if (bad < 1) { @@ -211,11 +211,11 @@ static errno_t hr_raid4_write(hr_volume_t *vol, uint64_t extent, aoff64_t ba, return rc; } - xorbuf = malloc(vol->bsize); + xorbuf = malloc(len); if (xorbuf == NULL) return ENOMEM; - buf = malloc(vol->bsize); + buf = malloc(len); if (buf == NULL) { free(xorbuf); return ENOMEM; @@ -227,57 +227,49 @@ static errno_t hr_raid4_write(hr_volume_t *vol, uint64_t extent, aoff64_t ba, * * write new parity */ - for (j = 0; j < cnt; j++) { - memset(xorbuf, 0, vol->bsize); - for (i = 1; i < vol->dev_no; i++) { - if (i == (size_t) bad) { - continue; - } else { - rc = block_read_direct(vol->extents[i].svc_id, - ba, 1, buf); - if (rc != EOK) - goto end; - xor(xorbuf, buf, vol->bsize); - } + memset(xorbuf, 0, len); + for (i = 1; i < vol->dev_no; i++) { + if (i == (size_t) bad) { + continue; + } else { + rc = block_read_direct(vol->extents[i].svc_id, + ba, cnt, buf); + if (rc != EOK) + goto end; + xor(xorbuf, buf, len); } - xor(xorbuf, data, vol->bsize); - rc = block_write_direct(vol->extents[0].svc_id, ba, 1, - xorbuf); - if (rc != EOK) - goto end; - data = (void *) ((uintptr_t) data + vol->bsize); - ba++; } + xor(xorbuf, data, len); + rc = block_write_direct(vol->extents[0].svc_id, ba, cnt, + xorbuf); + if (rc != EOK) + goto end; } else { /* * new parity = xor original data and old parity and new data * * write parity, new data */ - for (j = 0; j < cnt; j++) { - rc = block_read_direct(vol->extents[extent].svc_id, ba, - 1, xorbuf); - if (rc != EOK) - goto end; - rc = block_read_direct(vol->extents[0].svc_id, ba, 1, - buf); - if (rc != EOK) - goto end; - xor(xorbuf, buf, vol->bsize); + rc = block_read_direct(vol->extents[extent].svc_id, ba, cnt, + xorbuf); + if (rc != EOK) + goto end; + rc = block_read_direct(vol->extents[0].svc_id, ba, cnt, buf); + if (rc != EOK) + goto end; - xor(xorbuf, data, vol->bsize); + xor(xorbuf, buf, len); - rc = block_write_direct(vol->extents[0].svc_id, ba, 1, - xorbuf); - if (rc != EOK) - goto end; - rc = block_write_direct(vol->extents[extent].svc_id, - ba, 1, data); - if (rc != EOK) - goto end; - data = (void *) ((uintptr_t) data + vol->bsize); - ba++; - } + xor(xorbuf, data, len); + + rc = block_write_direct(vol->extents[0].svc_id, ba, cnt, + xorbuf); + if (rc != EOK) + goto end; + rc = block_write_direct(vol->extents[extent].svc_id, ba, cnt, + data); + if (rc != EOK) + goto end; } end: free(xorbuf); @@ -289,40 +281,40 @@ static errno_t hr_raid4_write_parity(hr_volume_t *vol, uint64_t extent, uint64_t block, const void *data, size_t cnt) { errno_t rc; - size_t i, j; + size_t i; void *xorbuf; void *buf; + uint64_t len = vol->bsize * cnt; - xorbuf = malloc(vol->bsize); + xorbuf = malloc(len); if (xorbuf == NULL) return ENOMEM; - buf = malloc(vol->bsize); + buf = malloc(len); if (buf == NULL) { free(xorbuf); return ENOMEM; } - for (j = 0; j < cnt; j++) { - memset(xorbuf, 0, vol->bsize); - for (i = 1; i < vol->dev_no; i++) { - if (i == extent) { - xor(xorbuf, data, vol->bsize); - } else { - rc = block_read_direct(vol->extents[i].svc_id, - block, 1, buf); - if (rc != EOK) - goto end; - xor(xorbuf, buf, vol->bsize); - } + /* + * parity = read and xor all other data extents, xor in new data + * + * XXX: subtract method + */ + memset(xorbuf, 0, len); + for (i = 1; i < vol->dev_no; i++) { + if (i == extent) { + xor(xorbuf, data, vol->bsize); + } else { + rc = block_read_direct(vol->extents[i].svc_id, block, + cnt, buf); + if (rc != EOK) + goto end; + xor(xorbuf, buf, len); } - rc = block_write_direct(vol->extents[0].svc_id, block, 1, - xorbuf); - if (rc != EOK) - goto end; - data = (void *) ((uintptr_t) data + vol->bsize); - block++; } + + rc = block_write_direct(vol->extents[0].svc_id, block, cnt, xorbuf); end: free(xorbuf); free(buf); From 1a60e645281c73de294a710aadd842ab59c68cb5 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 12 Nov 2024 16:24:08 +0100 Subject: [PATCH 057/324] hr: propagate ENOMEM in RAID4 --- uspace/srv/bd/hr/raid4.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/uspace/srv/bd/hr/raid4.c b/uspace/srv/bd/hr/raid4.c index 09819e3bc9..1668696948 100644 --- a/uspace/srv/bd/hr/raid4.c +++ b/uspace/srv/bd/hr/raid4.c @@ -410,6 +410,9 @@ static errno_t hr_raid4_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, goto error; } + if (rc == ENOMEM) + goto error; + if (rc == ENOENT) hr_update_ext_status(vol, extent, HR_EXT_MISSING); else if (rc != EOK) From d092d2ce6327b5c0c5ae85911271c24bbc5bd011 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 12 Nov 2024 22:06:04 +0100 Subject: [PATCH 058/324] hr: RAID{0,4}: cast void * to uint8_t * --- uspace/srv/bd/hr/raid0.c | 13 +++++++------ uspace/srv/bd/hr/raid4.c | 17 +++++++++-------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index 95d4c3d619..983c2f9ab6 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -114,12 +114,14 @@ static errno_t hr_raid0_bd_close(bd_srv_t *bd) } static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, - size_t cnt, void *data_read, const void *data_write, size_t size) + size_t cnt, void *dst, const void *src, size_t size) { hr_volume_t *vol = bd->srvs->sarg; errno_t rc; - uint64_t phys_block; + uint64_t phys_block, len; size_t left; + const uint8_t *data_write = src; + uint8_t *data_read = dst; /* propagate sync */ if (type == HR_BD_SYNC && ba == 0 && cnt == 0) { @@ -154,6 +156,7 @@ static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, while (left != 0) { phys_block = ext_stripe * strip_size + strip_off; cnt = min(left, strip_size - strip_off); + len = vol->bsize * cnt; hr_add_ba_offset(vol, &phys_block); switch (type) { case HR_BD_SYNC: @@ -166,14 +169,12 @@ static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, case HR_BD_READ: rc = block_read_direct(vol->extents[extent].svc_id, phys_block, cnt, data_read); - data_read = (void *) ((uintptr_t) data_read + - (vol->bsize * cnt)); + data_read += len; break; case HR_BD_WRITE: rc = block_write_direct(vol->extents[extent].svc_id, phys_block, cnt, data_write); - data_write = (void *) ((uintptr_t) data_write + - (vol->bsize * cnt)); + data_write += len; break; default: rc = EINVAL; diff --git a/uspace/srv/bd/hr/raid4.c b/uspace/srv/bd/hr/raid4.c index 1668696948..dbb3828478 100644 --- a/uspace/srv/bd/hr/raid4.c +++ b/uspace/srv/bd/hr/raid4.c @@ -334,12 +334,14 @@ static errno_t hr_raid4_bd_close(bd_srv_t *bd) } static errno_t hr_raid4_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, - size_t cnt, void *data_read, const void *data_write, size_t size) + size_t cnt, void *dst, const void *src, size_t size) { hr_volume_t *vol = bd->srvs->sarg; errno_t rc; - uint64_t phys_block; + uint64_t phys_block, len; size_t left; + const uint8_t *data_write = src; + uint8_t *data_read = dst; /* propagate sync */ if (type == HR_BD_SYNC && ba == 0 && cnt == 0) { @@ -374,6 +376,7 @@ static errno_t hr_raid4_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, while (left != 0) { phys_block = ext_stripe * strip_size + strip_off; cnt = min(left, strip_size - strip_off); + len = vol->bsize * cnt; hr_add_ba_offset(vol, &phys_block); switch (type) { case HR_BD_SYNC: @@ -395,15 +398,13 @@ static errno_t hr_raid4_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, rc = block_read_direct(vol->extents[extent].svc_id, phys_block, cnt, data_read); } - - data_read += vol->bsize * cnt; + data_read += len; break; case HR_BD_WRITE: retry_write: rc = hr_raid4_write(vol, extent, phys_block, data_write, cnt); - - data_write += vol->bsize * cnt; + data_write += len; break; default: rc = EINVAL; @@ -426,10 +427,10 @@ static errno_t hr_raid4_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, * rewind and retry */ if (type == HR_BD_WRITE) { - data_write -= vol->bsize * cnt; + data_write -= len; goto retry_write; } else if (type == HR_BD_WRITE) { - data_read -= vol->bsize * cnt; + data_read -= len; goto retry_read; } } else { From da0570a436685b8c434bef5717138cec2fddf7ca Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Wed, 13 Nov 2024 13:56:47 +0100 Subject: [PATCH 059/324] hr: RAID5 states, degraded R/W --- uspace/srv/bd/hr/raid5.c | 306 ++++++++++++++++++++++++++++++++++----- 1 file changed, 273 insertions(+), 33 deletions(-) diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 70a1e7acc5..faac731d97 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -64,6 +64,9 @@ static errno_t hr_raid5_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, static errno_t hr_raid5_bd_get_block_size(bd_srv_t *, size_t *); static errno_t hr_raid5_bd_get_num_blocks(bd_srv_t *, aoff64_t *); +static errno_t hr_raid5_write_parity(hr_volume_t *, uint64_t, uint64_t, + uint64_t, const void *, size_t); + static bd_ops_t hr_raid5_bd_ops = { .open = hr_raid5_bd_open, .close = hr_raid5_bd_close, @@ -74,6 +77,65 @@ static bd_ops_t hr_raid5_bd_ops = { .get_num_blocks = hr_raid5_bd_get_num_blocks }; +static errno_t hr_raid5_vol_usable(hr_volume_t *vol) +{ + if (vol->status == HR_VOL_ONLINE || + vol->status == HR_VOL_DEGRADED) + return EOK; + return EINVAL; +} + +/* + * Returns (-1) if all extents are online, + * else returns index of first bad one. + */ +static ssize_t hr_raid5_get_bad_ext(hr_volume_t *vol) +{ + for (size_t i = 0; i < vol->dev_no; i++) + if (vol->extents[i].status != HR_EXT_ONLINE) + return i; + return -1; +} + +static errno_t hr_raid5_update_vol_status(hr_volume_t *vol) +{ + hr_vol_status_t old_state = vol->status; + size_t bad = 0; + for (size_t i = 0; i < vol->dev_no; i++) + if (vol->extents[i].status != HR_EXT_ONLINE) + bad++; + + switch (bad) { + case 0: + if (old_state != HR_VOL_ONLINE) { + log_msg(LOG_DEFAULT, LVL_ERROR, + "RAID 5 has all extents online, " + "marking \"%s\" (%lu) as ONLINE", + vol->devname, vol->svc_id); + vol->status = HR_VOL_ONLINE; + } + return EOK; + case 1: + if (old_state != HR_VOL_DEGRADED) { + log_msg(LOG_DEFAULT, LVL_ERROR, + "RAID 5 array \"%s\" (%lu) has 1 extent inactive, " + "marking as DEGRADED", + vol->devname, vol->svc_id); + vol->status = HR_VOL_DEGRADED; + } + return EOK; + default: + if (old_state != HR_VOL_FAULTY) { + log_msg(LOG_DEFAULT, LVL_ERROR, + "RAID 5 array \"%s\" (%lu) has more than one 1 " + "extent inactive, marking as FAULTY", + vol->devname, vol->svc_id); + vol->status = HR_VOL_FAULTY; + } + return EINVAL; + } +} + static void xor(void *dst, const void *src, size_t size) { size_t i; @@ -84,49 +146,175 @@ static void xor(void *dst, const void *src, size_t size) *d++ ^= *s++; } -static errno_t write_parity(hr_volume_t *vol, uint64_t p_extent, - uint64_t extent, uint64_t block, const void *data, size_t cnt) +static errno_t hr_raid5_read_degraded(hr_volume_t *vol, uint64_t bad, + uint64_t block, void *data, size_t cnt) { errno_t rc; - size_t i, j; + size_t i; void *xorbuf; void *buf; + uint64_t len = vol->bsize * cnt; - xorbuf = malloc(vol->bsize); + xorbuf = malloc(len); if (xorbuf == NULL) return ENOMEM; - buf = malloc(vol->bsize); + buf = malloc(len); if (buf == NULL) { free(xorbuf); return ENOMEM; } - for (j = 0; j < cnt; j++) { - memset(xorbuf, 0, vol->bsize); - for (i = 0; i < vol->dev_no; i++) { - if (i == p_extent) - continue; + /* read all other extents in the stripe */ + memset(xorbuf, 0, len); + for (i = 0; i < vol->dev_no; i++) { + if (i == bad) { + continue; + } else { + rc = block_read_direct(vol->extents[i].svc_id, block, + cnt, buf); + if (rc != EOK) + goto end; + xor(xorbuf, buf, len); + } + } - if (i == extent) { - xor(xorbuf, data, vol->bsize); + memcpy(data, xorbuf, len); +end: + free(xorbuf); + free(buf); + return rc; +} + +static errno_t hr_raid5_write(hr_volume_t *vol, uint64_t p_extent, + uint64_t extent, aoff64_t ba, const void *data, size_t cnt) +{ + errno_t rc; + size_t i; + void *xorbuf; + void *buf; + uint64_t len = vol->bsize * cnt; + + ssize_t bad = hr_raid5_get_bad_ext(vol); + if (bad == -1 || (size_t)bad == p_extent) { + rc = block_write_direct(vol->extents[extent].svc_id, ba, cnt, + data); + if (rc != EOK) + return rc; + /* + * DEGRADED parity - skip parity write + */ + if ((size_t)bad == p_extent) + return EOK; + + rc = hr_raid5_write_parity(vol, p_extent, extent, ba, data, + cnt); + return rc; + } + + xorbuf = malloc(len); + if (xorbuf == NULL) + return ENOMEM; + + buf = malloc(len); + if (buf == NULL) { + free(xorbuf); + return ENOMEM; + } + + if (extent == (size_t) bad) { + /* + * new parity = read other and xor in new data + * + * write new parity + */ + memset(xorbuf, 0, len); + for (i = 1; i < vol->dev_no; i++) { + if (i == (size_t) bad) { + continue; } else { rc = block_read_direct(vol->extents[i].svc_id, - block, 1, buf); + ba, cnt, buf); if (rc != EOK) goto end; - xor(xorbuf, buf, vol->bsize); + xor(xorbuf, buf, len); } } + xor(xorbuf, data, len); + rc = block_write_direct(vol->extents[p_extent].svc_id, ba, cnt, + xorbuf); + if (rc != EOK) + goto end; + } else { + /* + * new parity = xor original data and old parity and new data + * + * write parity, new data + */ + rc = block_read_direct(vol->extents[extent].svc_id, ba, cnt, + xorbuf); + if (rc != EOK) + goto end; + rc = block_read_direct(vol->extents[p_extent].svc_id, ba, cnt, + buf); + if (rc != EOK) + goto end; + + xor(xorbuf, buf, len); - rc = block_write_direct(vol->extents[p_extent].svc_id, block, 1, + xor(xorbuf, data, len); + + rc = block_write_direct(vol->extents[p_extent].svc_id, ba, cnt, xorbuf); if (rc != EOK) goto end; - data = (void *) ((uintptr_t) data + vol->bsize); - block++; + rc = block_write_direct(vol->extents[extent].svc_id, ba, cnt, + data); + if (rc != EOK) + goto end; + } +end: + free(xorbuf); + free(buf); + return rc; +} + +static errno_t hr_raid5_write_parity(hr_volume_t *vol, uint64_t p_extent, + uint64_t extent, uint64_t block, const void *data, size_t cnt) +{ + errno_t rc; + size_t i; + void *xorbuf; + void *buf; + uint64_t len = vol->bsize * cnt; + + xorbuf = malloc(len); + if (xorbuf == NULL) + return ENOMEM; + + buf = malloc(len); + if (buf == NULL) { + free(xorbuf); + return ENOMEM; } + memset(xorbuf, 0, len); + for (i = 0; i < vol->dev_no; i++) { + if (i == p_extent) + continue; + if (i == extent) { + xor(xorbuf, data, vol->bsize); + } else { + rc = block_read_direct(vol->extents[i].svc_id, + block, cnt, buf); + if (rc != EOK) + goto end; + xor(xorbuf, buf, vol->bsize); + } + } + + rc = block_write_direct(vol->extents[p_extent].svc_id, block, cnt, + xorbuf); end: free(xorbuf); free(buf); @@ -146,12 +334,21 @@ static errno_t hr_raid5_bd_close(bd_srv_t *bd) } static errno_t hr_raid5_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, - size_t cnt, void *data_read, const void *data_write, size_t size) + size_t cnt, void *dst, const void *src, size_t size) { hr_volume_t *vol = bd->srvs->sarg; errno_t rc; - uint64_t phys_block; + uint64_t phys_block, len; size_t left; + const uint8_t *data_write = src; + uint8_t *data_read = dst; + + /* propagate sync */ + if (type == HR_BD_SYNC && ba == 0 && cnt == 0) { + hr_sync_all_extents(vol); + rc = hr_raid5_update_vol_status(vol); + return rc; + } if (type == HR_BD_READ || type == HR_BD_WRITE) if (size < cnt * vol->bsize) @@ -174,41 +371,79 @@ static errno_t hr_raid5_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, fibril_mutex_lock(&vol->lock); + rc = hr_raid5_vol_usable(vol); + if (rc != EOK) { + fibril_mutex_unlock(&vol->lock); + return EIO; + } + left = cnt; while (left != 0) { phys_block = ext_stripe * strip_size + strip_off; cnt = min(left, strip_size - strip_off); + len = vol->bsize * cnt; hr_add_ba_offset(vol, &phys_block); switch (type) { case HR_BD_SYNC: + if (vol->extents[extent].status != HR_EXT_ONLINE) + break; rc = block_sync_cache(vol->extents[extent].svc_id, phys_block, cnt); + /* allow unsupported sync */ + if (rc == ENOTSUP) + rc = EOK; break; case HR_BD_READ: - rc = block_read_direct(vol->extents[extent].svc_id, - phys_block, cnt, data_read); - data_read = (void *) ((uintptr_t) data_read + - (vol->bsize * cnt)); + retry_read: + ssize_t bad = hr_raid5_get_bad_ext(vol); + if (bad > 0 && extent == (size_t) bad) { + rc = hr_raid5_read_degraded(vol, bad, + phys_block, data_read, cnt); + } else { + rc = block_read_direct(vol->extents[extent].svc_id, + phys_block, cnt, data_read); + } + data_read += len; break; case HR_BD_WRITE: - rc = block_write_direct(vol->extents[extent].svc_id, - phys_block, cnt, data_write); - if (rc != EOK) - goto error; - rc = write_parity(vol, p_extent, extent, phys_block, + retry_write: + rc = hr_raid5_write(vol, p_extent, extent, phys_block, data_write, cnt); - if (rc != EOK) - goto error; - data_write = (void *) ((uintptr_t) data_write + - (vol->bsize * cnt)); + data_write += len; break; default: rc = EINVAL; + goto error; } - if (rc != EOK) + if (rc == ENOMEM) goto error; + if (rc == ENOENT) + hr_update_ext_status(vol, extent, HR_EXT_MISSING); + else if (rc != EOK) + hr_update_ext_status(vol, extent, HR_EXT_FAILED); + + if (rc != EOK) { + rc = hr_raid5_update_vol_status(vol); + if (rc == EOK) { + /* + * State changed from ONLINE -> DEGRADED, + * rewind and retry + */ + if (type == HR_BD_WRITE) { + data_write -= len; + goto retry_write; + } else if (type == HR_BD_WRITE) { + data_read -= len; + goto retry_read; + } + } else { + rc = EIO; + goto error; + } + } + left -= cnt; strip_off = 0; if (extent + 1 >= vol->dev_no || @@ -223,6 +458,7 @@ static errno_t hr_raid5_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, } error: + (void) hr_raid5_update_vol_status(vol); fibril_mutex_unlock(&vol->lock); return rc; } @@ -272,6 +508,10 @@ errno_t hr_raid5_create(hr_volume_t *new_volume) return EINVAL; } + rc = hr_raid5_update_vol_status(new_volume); + if (rc != EOK) + return rc; + bd_srvs_init(&new_volume->hr_bds); new_volume->hr_bds.ops = &hr_raid5_bd_ops; new_volume->hr_bds.sarg = new_volume; From fde02a615978e0487d670a581fed9798d5ad7121 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 15 Nov 2024 15:38:38 +0100 Subject: [PATCH 060/324] hr: be more careful with assembly from metadata Rewrite vol->extents only after all metadata was successfully read and validated. --- uspace/srv/bd/hr/superblock.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index eeded00c51..beb10f8844 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -132,11 +132,8 @@ errno_t hr_fill_vol_from_meta(hr_volume_t *vol) return ENOMEM; service_id_t cfg_svc_id_order[HR_MAXDEVS] = { 0 }; - for (size_t i = 0; i < vol->dev_no; i++) { + for (size_t i = 0; i < vol->dev_no; i++) cfg_svc_id_order[i] = vol->extents[i].svc_id; - vol->extents[i].svc_id = 0; - vol->extents[i].status = HR_EXT_MISSING; - } int32_t md_order[HR_MAXDEVS] = { 0 }; for (size_t i = 0; i < vol->dev_no; i++) { @@ -153,6 +150,12 @@ errno_t hr_fill_vol_from_meta(hr_volume_t *vol) md_order[i] = uint32_t_le2host(metadata->index); } + for (size_t i = 0; i < vol->dev_no; i++) { + vol->extents[i].svc_id = 0; + vol->extents[i].status = HR_EXT_MISSING; + } + + /* sort */ for (size_t i = 0; i < vol->dev_no; i++) { for (size_t j = 0; j < vol->dev_no; j++) { if (i == (uint32_t) md_order[j]) { From 8f7e1b175c21afedb3d71f955eab675a5d215b3d Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 15 Nov 2024 16:03:11 +0100 Subject: [PATCH 061/324] hrctl: rename flag --stop (-T) to --destroy (-D) --- uspace/app/hrctl/hrctl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index 5c2b6d8f44..dca2107cf4 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -57,7 +57,7 @@ static const char usage_str[] = " sample file at: " HRCTL_SAMPLE_CONFIG_PATH "\n" " -A, --assemble-file=PATH create an array from file\n" " -s, --status display status of active arrays\n" - " -T, --stop stop an active array\n" + " -D, --destroy destroy/disassemble an active array\n" " -F, --fail-extent fail an extent, use with -T and set it before\n" " -c, --create=NAME create new array\n" " -a, --assemble=NAME assemble an existing array\n" @@ -87,7 +87,7 @@ static struct option const long_options[] = { { "level", required_argument, 0, 'l' }, { "create-file", required_argument, 0, 'C' }, { "assemble-file", required_argument, 0, 'A' }, - { "stop", required_argument, 0, 'T' }, + { "destroy", required_argument, 0, 'D' }, { "fail-extent", required_argument, 0, 'F' }, { 0, 0, 0, 0 } }; @@ -243,7 +243,7 @@ int main(int argc, char **argv) optind = 0; while (c != -1) { - c = getopt_long(argc, argv, "hsC:c:A:a:l:0145Ln:T:F:", + c = getopt_long(argc, argv, "hsC:c:A:a:l:0145Ln:D:F:", long_options, NULL); switch (c) { case 'h': @@ -287,7 +287,7 @@ int main(int argc, char **argv) str_cpy(cfg->devname, sizeof(cfg->devname), optarg); assemble = true; break; - case 'T': + case 'D': rc = hr_stop(optarg, fail_extent); free(cfg); if (rc != EOK) { From 972b0116390b7fd106c18281b087334b4fda89fd Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 15 Nov 2024 16:30:29 +0100 Subject: [PATCH 062/324] hrctl: update usage Add a note to usage about automatic prepending of "devices/" prefix to specified array device name when creating or assembling a volume. --- uspace/app/hrctl/hrctl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index dca2107cf4..6949ed3d38 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -69,6 +69,9 @@ static const char usage_str[] = " -4 parity on one extent\n" " -5 distributed parity\n" "\n" + "When specifying name for creation or assembly, the device name\n" + "is automatically prepended with \"devices/\" prefix.\n" + "\n" "Example usage:\n" " hrctl --create hr0 -0 -n 2 devices/\\hw\\0 devices/\\hw\\1\n" " - creates new mirroring RAID device named /hr0 consisting\n" From bd51105efab562b47923c618d89a9add0239939d Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 15 Nov 2024 16:58:25 +0100 Subject: [PATCH 063/324] hr: util.h: add DPRINTF and ERR_PRINTF macros These macros forward arguments to log_msg() with LVL_DEBUG and LVL_ERROR respectively. --- uspace/srv/bd/hr/util.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index 9834e070c1..faff0ff8a3 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -40,6 +40,12 @@ #include "var.h" +#define DPRINTF(format, ...) \ + log_msg(LOG_DEFAULT, LVL_DEBUG, format, ##__VA_ARGS__) + +#define ERR_PRINTF(format, ...) \ + log_msg(LOG_DEFAULT, LVL_ERROR, format, ##__VA_ARGS__) + extern errno_t hr_init_devs(hr_volume_t *); extern void hr_fini_devs(hr_volume_t *); extern errno_t hr_register_volume(hr_volume_t *); From 5d96f42774a462ff9e2be60cf854ed0f78a60756 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 15 Nov 2024 17:08:11 +0100 Subject: [PATCH 064/324] hr: use DPRINTF and ERR_PRINTF macros from util.h --- uspace/srv/bd/hr/hr.c | 35 +++++++-------- uspace/srv/bd/hr/raid0.c | 12 +++--- uspace/srv/bd/hr/raid1.c | 22 ++++------ uspace/srv/bd/hr/raid4.c | 20 ++++----- uspace/srv/bd/hr/raid5.c | 20 ++++----- uspace/srv/bd/hr/superblock.c | 23 +++++----- uspace/srv/bd/hr/util.c | 80 +++++++++++++++++++---------------- 7 files changed, 100 insertions(+), 112 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 1fea425716..730c7d96ff 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -61,8 +61,7 @@ static service_id_t ctl_sid; static hr_volume_t *hr_get_volume(service_id_t svc_id) { - log_msg(LOG_DEFAULT, LVL_DEBUG, "hr_get_volume(): (%" PRIun ")", - svc_id); + DPRINTF("hr_get_volume(): (%" PRIun ")\n", svc_id); fibril_mutex_lock(&hr_volumes_lock); list_foreach(hr_volumes, lvolumes, hr_volume_t, volume) { @@ -78,8 +77,7 @@ static hr_volume_t *hr_get_volume(service_id_t svc_id) static errno_t hr_remove_volume(service_id_t svc_id) { - log_msg(LOG_DEFAULT, LVL_DEBUG, "hr_remove_volume(): (%" PRIun ")", - svc_id); + DPRINTF("hr_remove_volume(): (%" PRIun ")\n", svc_id); fibril_mutex_lock(&hr_volumes_lock); list_foreach(hr_volumes, lvolumes, hr_volume_t, volume) { @@ -98,7 +96,7 @@ static errno_t hr_remove_volume(service_id_t svc_id) static void hr_create_srv(ipc_call_t *icall, bool assemble) { - log_msg(LOG_DEFAULT, LVL_NOTE, "hr_create_srv()"); + DPRINTF("hr_create_srv()\n"); errno_t rc; size_t i, size; @@ -140,6 +138,8 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) if (!assemble) { for (i = 0; i < cfg->dev_no; i++) { if (cfg->devs[i] == 0) { + ERR_PRINTF("missing device provided for array " + "creation, aborting"); free(cfg); async_answer_0(icall, EINVAL); return; @@ -204,8 +204,7 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) new_volume->hr_ops.init = hr_raid5_init; break; default: - log_msg(LOG_DEFAULT, LVL_ERROR, - "level %d not implemented yet", new_volume->level); + ERR_PRINTF("unkown level: %d, aborting\n", new_volume->level); rc = EINVAL; goto error; } @@ -231,12 +230,10 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) fibril_mutex_unlock(&hr_volumes_lock); if (assemble) { - log_msg(LOG_DEFAULT, LVL_NOTE, - "assembled volume \"%s\" (%" PRIun ")", + DPRINTF("assembled volume \"%s\" (%" PRIun ")\n", new_volume->devname, new_volume->svc_id); } else { - log_msg(LOG_DEFAULT, LVL_NOTE, - "created volume \"%s\" (%" PRIun ")", + DPRINTF("created volume \"%s\" (%" PRIun ")\n", new_volume->devname, new_volume->svc_id); } @@ -252,7 +249,7 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) static void hr_stop_srv(ipc_call_t *icall) { - log_msg(LOG_DEFAULT, LVL_NOTE, "hr_stop_srv()"); + DPRINTF("hr_stop_srv()\n"); errno_t rc = EOK; service_id_t svc_id; @@ -286,7 +283,7 @@ static void hr_stop_srv(ipc_call_t *icall) static void hr_print_status_srv(ipc_call_t *icall) { - log_msg(LOG_DEFAULT, LVL_NOTE, "hr_status_srv()"); + DPRINTF("hr_status_srv()\n"); errno_t rc; size_t vol_cnt = 0; @@ -350,7 +347,7 @@ static void hr_print_status_srv(ipc_call_t *icall) static void hr_ctl_conn(ipc_call_t *icall, void *arg) { - log_msg(LOG_DEFAULT, LVL_NOTE, "hr_ctl_conn()"); + DPRINTF("hr_ctl_conn()\n"); async_accept_0(icall); @@ -385,7 +382,7 @@ static void hr_ctl_conn(ipc_call_t *icall, void *arg) static void hr_client_conn(ipc_call_t *icall, void *arg) { - log_msg(LOG_DEFAULT, LVL_NOTE, "hr_client_conn()"); + DPRINTF("hr_client_conn()\n"); hr_volume_t *vol; @@ -394,7 +391,7 @@ static void hr_client_conn(ipc_call_t *icall, void *arg) if (svc_id == ctl_sid) { hr_ctl_conn(icall, arg); } else { - log_msg(LOG_DEFAULT, LVL_NOTE, "bd_conn()"); + DPRINTF("bd_conn()\n"); vol = hr_get_volume(svc_id); if (vol == NULL) async_answer_0(icall, EINVAL); @@ -421,15 +418,13 @@ int main(int argc, char **argv) rc = loc_server_register(NAME, &hr_srv); if (rc != EOK) { - log_msg(LOG_DEFAULT, LVL_ERROR, - "failed registering server: %s", str_error(rc)); + ERR_PRINTF("failed registering server: %s", str_error(rc)); return EEXIST; } rc = loc_service_register(hr_srv, SERVICE_NAME_HR, &ctl_sid); if (rc != EOK) { - log_msg(LOG_DEFAULT, LVL_ERROR, - "failed registering service: %s", str_error(rc)); + ERR_PRINTF("failed registering service: %s", str_error(rc)); return EEXIST; } diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index 983c2f9ab6..31c80fa1ae 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -88,9 +88,8 @@ static errno_t hr_raid0_update_vol_status(hr_volume_t *vol) { for (size_t i = 0; i < vol->dev_no; i++) { if (vol->extents[i].status != HR_EXT_ONLINE) { - log_msg(LOG_DEFAULT, LVL_ERROR, - "RAID 0 needs all extents to be ONLINE, marking " - "\"%s\" (%lu) as FAULTY", + ERR_PRINTF("RAID 0 needs all extents to be ONLINE, " + "marking \"%s\" (%lu) as FAULTY", vol->devname, vol->svc_id); vol->status = HR_VOL_FAULTY; return EINVAL; @@ -103,13 +102,13 @@ static errno_t hr_raid0_update_vol_status(hr_volume_t *vol) static errno_t hr_raid0_bd_open(bd_srvs_t *bds, bd_srv_t *bd) { - log_msg(LOG_DEFAULT, LVL_NOTE, "hr_bd_open()"); + DPRINTF("hr_bd_open()\n"); return EOK; } static errno_t hr_raid0_bd_close(bd_srv_t *bd) { - log_msg(LOG_DEFAULT, LVL_NOTE, "hr_bd_close()"); + DPRINTF("hr_bd_close()\n"); return EOK; } @@ -245,8 +244,7 @@ errno_t hr_raid0_create(hr_volume_t *new_volume) assert(new_volume->level == HR_LVL_0); if (new_volume->dev_no < 2) { - log_msg(LOG_DEFAULT, LVL_ERROR, - "RAID 0 array needs at least 2 devices"); + ERR_PRINTF("RAID 0 array needs at least 2 devices"); return EINVAL; } diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 771017ab88..cd0f0d2458 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -94,27 +94,24 @@ static errno_t hr_raid1_update_vol_status(hr_volume_t *vol) if (healthy == 0) { if (old_state != HR_VOL_FAULTY) { - log_msg(LOG_DEFAULT, LVL_ERROR, - "RAID 1 needs at least 1 extent to be ONLINE, " - "marking \"%s\" (%lu) as FAULTY", + ERR_PRINTF("RAID 1 needs at least 1 extent to be" + "ONLINE, marking \"%s\" (%lu) volume as FAULTY", vol->devname, vol->svc_id); vol->status = HR_VOL_FAULTY; } return EINVAL; } else if (healthy < vol->dev_no) { if (old_state != HR_VOL_DEGRADED) { - log_msg(LOG_DEFAULT, LVL_ERROR, - "RAID 1 array \"%s\" (%lu) has some inactive " - "extents, marking as DEGRADED", + ERR_PRINTF("RAID 1 array \"%s\" (%lu) has some " + "inactive extent(s), marking volume as DEGRADED", vol->devname, vol->svc_id); vol->status = HR_VOL_DEGRADED; } return EOK; } else { if (old_state != HR_VOL_ONLINE) { - log_msg(LOG_DEFAULT, LVL_ERROR, - "RAID 1 array \"%s\" (%lu) has all extents active, " - "marking as ONLINE", + DPRINTF("RAID 1 array \"%s\" (%lu) has all extents " + "active, marking volume as ONLINE", vol->devname, vol->svc_id); vol->status = HR_VOL_ONLINE; } @@ -124,13 +121,13 @@ static errno_t hr_raid1_update_vol_status(hr_volume_t *vol) static errno_t hr_raid1_bd_open(bd_srvs_t *bds, bd_srv_t *bd) { - log_msg(LOG_DEFAULT, LVL_NOTE, "hr_bd_open()"); + DPRINTF("hr_bd_open()\n"); return EOK; } static errno_t hr_raid1_bd_close(bd_srv_t *bd) { - log_msg(LOG_DEFAULT, LVL_NOTE, "hr_bd_close()"); + DPRINTF("hr_bd_close()\n"); return EOK; } @@ -259,8 +256,7 @@ errno_t hr_raid1_create(hr_volume_t *new_volume) assert(new_volume->level == HR_LVL_1); if (new_volume->dev_no < 2) { - log_msg(LOG_DEFAULT, LVL_ERROR, - "RAID 1 array needs at least 2 devices"); + ERR_PRINTF("RAID 1 array needs at least 2 devices\n"); return EINVAL; } diff --git a/uspace/srv/bd/hr/raid4.c b/uspace/srv/bd/hr/raid4.c index dbb3828478..e1c1e763b6 100644 --- a/uspace/srv/bd/hr/raid4.c +++ b/uspace/srv/bd/hr/raid4.c @@ -108,8 +108,7 @@ static errno_t hr_raid4_update_vol_status(hr_volume_t *vol) switch (bad) { case 0: if (old_state != HR_VOL_ONLINE) { - log_msg(LOG_DEFAULT, LVL_ERROR, - "RAID 4 has all extents online, " + DPRINTF("RAID 4 has all extents online, " "marking \"%s\" (%lu) as ONLINE", vol->devname, vol->svc_id); vol->status = HR_VOL_ONLINE; @@ -117,18 +116,16 @@ static errno_t hr_raid4_update_vol_status(hr_volume_t *vol) return EOK; case 1: if (old_state != HR_VOL_DEGRADED) { - log_msg(LOG_DEFAULT, LVL_ERROR, - "RAID 4 array \"%s\" (%lu) has 1 extent inactive, " - "marking as DEGRADED", + ERR_PRINTF("RAID 4 array \"%s\" (%lu) has 1 extent " + "inactive, marking as DEGRADED", vol->devname, vol->svc_id); vol->status = HR_VOL_DEGRADED; } return EOK; default: if (old_state != HR_VOL_FAULTY) { - log_msg(LOG_DEFAULT, LVL_ERROR, - "RAID 4 array \"%s\" (%lu) has more than one 1 " - "extent inactive, marking as FAULTY", + ERR_PRINTF("RAID 4 array \"%s\" (%lu) has more " + "than one 1 extent inactive, marking as FAULTY", vol->devname, vol->svc_id); vol->status = HR_VOL_FAULTY; } @@ -323,13 +320,13 @@ static errno_t hr_raid4_write_parity(hr_volume_t *vol, uint64_t extent, static errno_t hr_raid4_bd_open(bd_srvs_t *bds, bd_srv_t *bd) { - log_msg(LOG_DEFAULT, LVL_NOTE, "hr_bd_open()"); + DPRINTF("hr_bd_open()\n"); return EOK; } static errno_t hr_raid4_bd_close(bd_srv_t *bd) { - log_msg(LOG_DEFAULT, LVL_NOTE, "hr_bd_close()"); + DPRINTF("hr_bd_close()\n"); return EOK; } @@ -494,8 +491,7 @@ errno_t hr_raid4_create(hr_volume_t *new_volume) assert(new_volume->level == HR_LVL_4); if (new_volume->dev_no < 3) { - log_msg(LOG_DEFAULT, LVL_ERROR, - "RAID 4 array needs at least 3 devices"); + ERR_PRINTF("RAID 4 array needs at least 3 devices"); return EINVAL; } diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index faac731d97..69806f864b 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -108,8 +108,7 @@ static errno_t hr_raid5_update_vol_status(hr_volume_t *vol) switch (bad) { case 0: if (old_state != HR_VOL_ONLINE) { - log_msg(LOG_DEFAULT, LVL_ERROR, - "RAID 5 has all extents online, " + DPRINTF("RAID 5 has all extents online, " "marking \"%s\" (%lu) as ONLINE", vol->devname, vol->svc_id); vol->status = HR_VOL_ONLINE; @@ -117,18 +116,16 @@ static errno_t hr_raid5_update_vol_status(hr_volume_t *vol) return EOK; case 1: if (old_state != HR_VOL_DEGRADED) { - log_msg(LOG_DEFAULT, LVL_ERROR, - "RAID 5 array \"%s\" (%lu) has 1 extent inactive, " - "marking as DEGRADED", + ERR_PRINTF("RAID 5 array \"%s\" (%lu) has 1 extent " + "inactive, marking as DEGRADED", vol->devname, vol->svc_id); vol->status = HR_VOL_DEGRADED; } return EOK; default: if (old_state != HR_VOL_FAULTY) { - log_msg(LOG_DEFAULT, LVL_ERROR, - "RAID 5 array \"%s\" (%lu) has more than one 1 " - "extent inactive, marking as FAULTY", + ERR_PRINTF("RAID 5 array \"%s\" (%lu) has more " + "than one 1 extent inactive, marking as FAULTY", vol->devname, vol->svc_id); vol->status = HR_VOL_FAULTY; } @@ -323,13 +320,13 @@ static errno_t hr_raid5_write_parity(hr_volume_t *vol, uint64_t p_extent, static errno_t hr_raid5_bd_open(bd_srvs_t *bds, bd_srv_t *bd) { - log_msg(LOG_DEFAULT, LVL_NOTE, "hr_bd_open()"); + DPRINTF("hr_bd_open()\n"); return EOK; } static errno_t hr_raid5_bd_close(bd_srv_t *bd) { - log_msg(LOG_DEFAULT, LVL_NOTE, "hr_bd_close()"); + DPRINTF("hr_bd_close()\n"); return EOK; } @@ -503,8 +500,7 @@ errno_t hr_raid5_create(hr_volume_t *new_volume) assert(new_volume->level == HR_LVL_5); if (new_volume->dev_no < 3) { - log_msg(LOG_DEFAULT, LVL_ERROR, - "RAID 5 array needs at least 3 devices"); + ERR_PRINTF("RAID 5 array needs at least 3 devices"); return EINVAL; } diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index beb10f8844..b77ffe75c1 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -53,7 +53,7 @@ static errno_t read_metadata(service_id_t, hr_metadata_t *); errno_t hr_write_meta_to_vol(hr_volume_t *vol) { - log_msg(LOG_DEFAULT, LVL_NOTE, "hr_write_meta_to_vol()"); + DPRINTF("hr_write_meta_to_vol()\n"); errno_t rc; size_t i; @@ -70,13 +70,12 @@ errno_t hr_write_meta_to_vol(hr_volume_t *vol) meta_blkno *= vol->dev_no; if (vol->nblocks < meta_blkno) { - log_msg(LOG_DEFAULT, LVL_ERROR, - "not enough blocks to write metadata"); + ERR_PRINTF("not enough blocks to write metadat\n"); rc = EINVAL; goto error; } else if (vol->nblocks == meta_blkno) { - log_msg(LOG_DEFAULT, LVL_ERROR, - "there would be zero data blocks after writing metadata, aborting"); + ERR_PRINTF("there would be zero data blocks after writing " + "metadata, aborting"); rc = EINVAL; goto error; } @@ -114,7 +113,7 @@ errno_t hr_write_meta_to_vol(hr_volume_t *vol) static errno_t validate_meta(hr_metadata_t *md) { if (uint64_t_le2host(md->magic) != HR_MAGIC) { - printf("invalid magic\n"); + ERR_PRINTF("invalid magic\n"); return EINVAL; } return EOK; @@ -122,7 +121,7 @@ static errno_t validate_meta(hr_metadata_t *md) errno_t hr_fill_vol_from_meta(hr_volume_t *vol) { - log_msg(LOG_DEFAULT, LVL_NOTE, "hr_get_vol_from_meta()"); + DPRINTF("hr_get_vol_from_meta()\n"); errno_t rc; hr_metadata_t *metadata; @@ -170,8 +169,8 @@ errno_t hr_fill_vol_from_meta(hr_volume_t *vol) */ if (vol->dev_no != uint32_t_le2host(metadata->extent_no)) { - log_msg(LOG_DEFAULT, LVL_ERROR, - "number of divices in array differ: specified %zu, metadata states %u", + ERR_PRINTF("number of divices in array differ: specified %zu, " + "metadata states %u", vol->dev_no, uint32_t_le2host(metadata->extent_no)); rc = EINVAL; goto end; @@ -184,9 +183,9 @@ errno_t hr_fill_vol_from_meta(hr_volume_t *vol) vol->strip_size = uint32_t_le2host(metadata->strip_size); if (str_cmp(metadata->devname, vol->devname) != 0) { - log_msg(LOG_DEFAULT, LVL_NOTE, - "devname on metadata (%s) and config (%s) differ, using config", - metadata->devname, vol->devname); + log_msg(LOG_DEFAULT, LVL_WARN, + "devname on metadata (%s) and config (%s) differ, " + "using config", metadata->devname, vol->devname); } end: free(metadata); diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 9787afce85..29abf3bacb 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -49,25 +49,27 @@ extern loc_srv_t *hr_srv; errno_t hr_init_devs(hr_volume_t *vol) { - log_msg(LOG_DEFAULT, LVL_NOTE, "hr_init_devs()"); + DPRINTF("hr_init_devs()\n"); errno_t rc; size_t i; + hr_extent_t *extent; for (i = 0; i < vol->dev_no; i++) { - if (vol->extents[i].svc_id == 0) { - vol->extents[i].status = HR_EXT_MISSING; + extent = &vol->extents[i]; + if (extent->svc_id == 0) { + extent->status = HR_EXT_MISSING; continue; } - rc = block_init(vol->extents[i].svc_id); - vol->extents[i].status = HR_EXT_ONLINE; - log_msg(LOG_DEFAULT, LVL_DEBUG, - "hr_init_devs(): initing (%" PRIun ")", - vol->extents[i].svc_id); + + DPRINTF("hr_init_devs(): block_init() on (%lu)\n", + extent->svc_id); + rc = block_init(extent->svc_id); + extent->status = HR_EXT_ONLINE; + if (rc != EOK) { - log_msg(LOG_DEFAULT, LVL_ERROR, - "hr_init_devs(): initing (%" PRIun ") failed, aborting", - vol->extents[i].svc_id); + ERR_PRINTF("hr_init_devs(): initing (%lu) failed, " + "aborting\n", extent->svc_id); break; } } @@ -77,51 +79,54 @@ errno_t hr_init_devs(hr_volume_t *vol) void hr_fini_devs(hr_volume_t *vol) { - log_msg(LOG_DEFAULT, LVL_NOTE, "hr_fini_devs()"); + DPRINTF("hr_fini_devs()\n"); size_t i; - for (i = 0; i < vol->dev_no; i++) - if (vol->extents[i].status != HR_EXT_MISSING) + for (i = 0; i < vol->dev_no; i++) { + if (vol->extents[i].status != HR_EXT_MISSING) { + DPRINTF("hr_fini_devs(): block_fini() on (%lu)\n", + vol->extents[i].svc_id); block_fini(vol->extents[i].svc_id); + } + } } -errno_t hr_register_volume(hr_volume_t *new_volume) +errno_t hr_register_volume(hr_volume_t *vol) { - log_msg(LOG_DEFAULT, LVL_NOTE, "hr_register_volume()"); + DPRINTF("hr_register_volume()\n"); errno_t rc; service_id_t new_id; category_id_t cat_id; char *fullname = NULL; + char *devname = vol->devname; - if (asprintf(&fullname, "devices/%s", new_volume->devname) < 0) + if (asprintf(&fullname, "devices/%s", devname) < 0) return ENOMEM; rc = loc_service_register(hr_srv, fullname, &new_id); if (rc != EOK) { - log_msg(LOG_DEFAULT, LVL_ERROR, - "unable to register device \"%s\": %s\n", - new_volume->devname, str_error(rc)); + ERR_PRINTF("unable to register device \"%s\": %s\n", + fullname, str_error(rc)); goto error; } rc = loc_category_get_id("raid", &cat_id, IPC_FLAG_BLOCKING); if (rc != EOK) { - log_msg(LOG_DEFAULT, LVL_ERROR, - "failed resolving category \"raid\": %s\n", str_error(rc)); + ERR_PRINTF("failed resolving category \"raid\": %s\n", + str_error(rc)); goto error; } rc = loc_service_add_to_cat(hr_srv, new_id, cat_id); if (rc != EOK) { - log_msg(LOG_DEFAULT, LVL_ERROR, - "failed adding \"%s\" to category \"raid\": %s\n", - new_volume->devname, str_error(rc)); + ERR_PRINTF("failed adding \"%s\" to category \"raid\": %s\n", + fullname, str_error(rc)); goto error; } - new_volume->svc_id = new_id; + vol->svc_id = new_id; error: free(fullname); @@ -130,7 +135,7 @@ errno_t hr_register_volume(hr_volume_t *new_volume) errno_t hr_check_devs(hr_volume_t *vol, uint64_t *rblkno, size_t *rbsize) { - log_msg(LOG_DEFAULT, LVL_NOTE, "hr_check_devs()"); + DPRINTF("hr_check_devs()\n"); errno_t rc; size_t i, bsize; @@ -138,40 +143,43 @@ errno_t hr_check_devs(hr_volume_t *vol, uint64_t *rblkno, size_t *rbsize) size_t last_bsize = 0; uint64_t last_nblocks = 0; uint64_t total_blocks = 0; + hr_extent_t *extent; for (i = 0; i < vol->dev_no; i++) { - if (vol->extents[i].status == HR_EXT_MISSING) + extent = &vol->extents[i]; + if (extent->status == HR_EXT_MISSING) continue; - rc = block_get_nblocks(vol->extents[i].svc_id, &nblocks); + rc = block_get_nblocks(extent->svc_id, &nblocks); if (rc != EOK) goto error; if (last_nblocks != 0 && nblocks != last_nblocks) { - log_msg(LOG_DEFAULT, LVL_ERROR, - "number of blocks differs"); + ERR_PRINTF("number of blocks differs\n"); rc = EINVAL; goto error; } + total_blocks += nblocks; last_nblocks = nblocks; } for (i = 0; i < vol->dev_no; i++) { - if (vol->extents[i].status == HR_EXT_MISSING) + extent = &vol->extents[i]; + if (extent->status == HR_EXT_MISSING) continue; - rc = block_get_bsize(vol->extents[i].svc_id, &bsize); + rc = block_get_bsize(extent->svc_id, &bsize); if (rc != EOK) goto error; if (last_bsize != 0 && bsize != last_bsize) { - log_msg(LOG_DEFAULT, LVL_ERROR, "block sizes differ"); + ERR_PRINTF("block sizes differ\n"); rc = EINVAL; goto error; } + last_bsize = bsize; } if ((bsize % 512) != 0) { - log_msg(LOG_DEFAULT, LVL_ERROR, - "block size not multiple of 512"); + ERR_PRINTF("block size not multiple of 512\n"); return EINVAL; } From 733564aabcdf520b4c2075050c32aba43293cbfd Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 15 Nov 2024 17:27:17 +0100 Subject: [PATCH 065/324] hr: add all fcn prototypes in raid implementations Also restructure the file in order: create(), init(), public BD ops, internal util functions and io ops. --- uspace/srv/bd/hr/raid0.c | 186 ++++++++++++++++++------------------ uspace/srv/bd/hr/raid1.c | 187 ++++++++++++++++++------------------ uspace/srv/bd/hr/raid4.c | 196 ++++++++++++++++++++------------------ uspace/srv/bd/hr/raid5.c | 199 +++++++++++++++++++++------------------ 4 files changed, 403 insertions(+), 365 deletions(-) diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index 31c80fa1ae..dc80df92d7 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -53,6 +53,12 @@ extern loc_srv_t *hr_srv; +static errno_t hr_raid0_check_vol_status(hr_volume_t *); +static errno_t hr_raid0_update_vol_status(hr_volume_t *); +static errno_t hr_raid0_bd_op(hr_bd_op_type_t, bd_srv_t *, aoff64_t, size_t, + void *, const void *, size_t); + +/* bdops */ static errno_t hr_raid0_bd_open(bd_srvs_t *, bd_srv_t *); static errno_t hr_raid0_bd_close(bd_srv_t *); static errno_t hr_raid0_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, @@ -73,6 +79,96 @@ static bd_ops_t hr_raid0_bd_ops = { .get_num_blocks = hr_raid0_bd_get_num_blocks }; +errno_t hr_raid0_create(hr_volume_t *new_volume) +{ + errno_t rc; + + assert(new_volume->level == HR_LVL_0); + + if (new_volume->dev_no < 2) { + ERR_PRINTF("RAID 0 array needs at least 2 devices"); + return EINVAL; + } + + rc = hr_raid0_update_vol_status(new_volume); + if (rc != EOK) + return rc; + + bd_srvs_init(&new_volume->hr_bds); + new_volume->hr_bds.ops = &hr_raid0_bd_ops; + new_volume->hr_bds.sarg = new_volume; + + rc = hr_register_volume(new_volume); + + return rc; +} + +errno_t hr_raid0_init(hr_volume_t *vol) +{ + errno_t rc; + size_t bsize; + uint64_t total_blkno; + + assert(vol->level == HR_LVL_0); + + rc = hr_check_devs(vol, &total_blkno, &bsize); + if (rc != EOK) + return rc; + + vol->nblocks = total_blkno; + vol->bsize = bsize; + vol->data_offset = HR_DATA_OFF; + vol->data_blkno = vol->nblocks - (vol->data_offset * vol->dev_no); + vol->strip_size = HR_STRIP_SIZE; + + return EOK; +} + +static errno_t hr_raid0_bd_open(bd_srvs_t *bds, bd_srv_t *bd) +{ + DPRINTF("hr_bd_open()\n"); + return EOK; +} + +static errno_t hr_raid0_bd_close(bd_srv_t *bd) +{ + DPRINTF("hr_bd_close()\n"); + return EOK; +} + +static errno_t hr_raid0_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) +{ + return hr_raid0_bd_op(HR_BD_SYNC, bd, ba, cnt, NULL, NULL, 0); +} + +static errno_t hr_raid0_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, + void *buf, size_t size) +{ + return hr_raid0_bd_op(HR_BD_READ, bd, ba, cnt, buf, NULL, size); +} + +static errno_t hr_raid0_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, + const void *data, size_t size) +{ + return hr_raid0_bd_op(HR_BD_WRITE, bd, ba, cnt, NULL, data, size); +} + +static errno_t hr_raid0_bd_get_block_size(bd_srv_t *bd, size_t *rsize) +{ + hr_volume_t *vol = bd->srvs->sarg; + + *rsize = vol->bsize; + return EOK; +} + +static errno_t hr_raid0_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb) +{ + hr_volume_t *vol = bd->srvs->sarg; + + *rnb = vol->data_blkno; + return EOK; +} + static errno_t hr_raid0_check_vol_status(hr_volume_t *vol) { if (vol->status == HR_VOL_ONLINE) @@ -100,18 +196,6 @@ static errno_t hr_raid0_update_vol_status(hr_volume_t *vol) return EOK; } -static errno_t hr_raid0_bd_open(bd_srvs_t *bds, bd_srv_t *bd) -{ - DPRINTF("hr_bd_open()\n"); - return EOK; -} - -static errno_t hr_raid0_bd_close(bd_srv_t *bd) -{ - DPRINTF("hr_bd_close()\n"); - return EOK; -} - static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, size_t cnt, void *dst, const void *src, size_t size) { @@ -204,83 +288,5 @@ static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, return rc; } -static errno_t hr_raid0_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) -{ - return hr_raid0_bd_op(HR_BD_SYNC, bd, ba, cnt, NULL, NULL, 0); -} - -static errno_t hr_raid0_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, - void *buf, size_t size) -{ - return hr_raid0_bd_op(HR_BD_READ, bd, ba, cnt, buf, NULL, size); -} - -static errno_t hr_raid0_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, - const void *data, size_t size) -{ - return hr_raid0_bd_op(HR_BD_WRITE, bd, ba, cnt, NULL, data, size); -} - -static errno_t hr_raid0_bd_get_block_size(bd_srv_t *bd, size_t *rsize) -{ - hr_volume_t *vol = bd->srvs->sarg; - - *rsize = vol->bsize; - return EOK; -} - -static errno_t hr_raid0_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb) -{ - hr_volume_t *vol = bd->srvs->sarg; - - *rnb = vol->data_blkno; - return EOK; -} - -errno_t hr_raid0_create(hr_volume_t *new_volume) -{ - errno_t rc; - - assert(new_volume->level == HR_LVL_0); - - if (new_volume->dev_no < 2) { - ERR_PRINTF("RAID 0 array needs at least 2 devices"); - return EINVAL; - } - - rc = hr_raid0_update_vol_status(new_volume); - if (rc != EOK) - return rc; - - bd_srvs_init(&new_volume->hr_bds); - new_volume->hr_bds.ops = &hr_raid0_bd_ops; - new_volume->hr_bds.sarg = new_volume; - - rc = hr_register_volume(new_volume); - - return rc; -} - -errno_t hr_raid0_init(hr_volume_t *vol) -{ - errno_t rc; - size_t bsize; - uint64_t total_blkno; - - assert(vol->level == HR_LVL_0); - - rc = hr_check_devs(vol, &total_blkno, &bsize); - if (rc != EOK) - return rc; - - vol->nblocks = total_blkno; - vol->bsize = bsize; - vol->data_offset = HR_DATA_OFF; - vol->data_blkno = vol->nblocks - (vol->data_offset * vol->dev_no); - vol->strip_size = HR_STRIP_SIZE; - - return EOK; -} - /** @} */ diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index cd0f0d2458..d62c2489b5 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -52,6 +52,13 @@ extern loc_srv_t *hr_srv; +static errno_t hr_raid1_check_vol_status(hr_volume_t *); +static errno_t hr_raid1_update_vol_status(hr_volume_t *); +static void handle_extent_error(hr_volume_t *, size_t, errno_t); +static errno_t hr_raid1_bd_op(hr_bd_op_type_t, bd_srv_t *, aoff64_t, size_t, + void *, const void *, size_t); + +/* bdops */ static errno_t hr_raid1_bd_open(bd_srvs_t *, bd_srv_t *); static errno_t hr_raid1_bd_close(bd_srv_t *); static errno_t hr_raid1_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, @@ -72,6 +79,96 @@ static bd_ops_t hr_raid1_bd_ops = { .get_num_blocks = hr_raid1_bd_get_num_blocks }; +errno_t hr_raid1_create(hr_volume_t *new_volume) +{ + errno_t rc; + + assert(new_volume->level == HR_LVL_1); + + if (new_volume->dev_no < 2) { + ERR_PRINTF("RAID 1 array needs at least 2 devices\n"); + return EINVAL; + } + + rc = hr_raid1_update_vol_status(new_volume); + if (rc != EOK) + return rc; + + bd_srvs_init(&new_volume->hr_bds); + new_volume->hr_bds.ops = &hr_raid1_bd_ops; + new_volume->hr_bds.sarg = new_volume; + + rc = hr_register_volume(new_volume); + + return rc; +} + +errno_t hr_raid1_init(hr_volume_t *vol) +{ + errno_t rc; + size_t bsize; + uint64_t total_blkno; + + assert(vol->level == HR_LVL_1); + + rc = hr_check_devs(vol, &total_blkno, &bsize); + if (rc != EOK) + return rc; + + vol->nblocks = total_blkno / vol->dev_no; + vol->bsize = bsize; + vol->data_offset = HR_DATA_OFF; + vol->data_blkno = vol->nblocks - vol->data_offset; + vol->strip_size = 0; + + return EOK; +} + +static errno_t hr_raid1_bd_open(bd_srvs_t *bds, bd_srv_t *bd) +{ + DPRINTF("hr_bd_open()\n"); + return EOK; +} + +static errno_t hr_raid1_bd_close(bd_srv_t *bd) +{ + DPRINTF("hr_bd_close()\n"); + return EOK; +} + +static errno_t hr_raid1_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) +{ + return hr_raid1_bd_op(HR_BD_SYNC, bd, ba, cnt, NULL, NULL, 0); +} + +static errno_t hr_raid1_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, + void *buf, size_t size) +{ + return hr_raid1_bd_op(HR_BD_READ, bd, ba, cnt, buf, NULL, size); +} + +static errno_t hr_raid1_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, + const void *data, size_t size) +{ + return hr_raid1_bd_op(HR_BD_WRITE, bd, ba, cnt, NULL, data, size); +} + +static errno_t hr_raid1_bd_get_block_size(bd_srv_t *bd, size_t *rsize) +{ + hr_volume_t *vol = bd->srvs->sarg; + + *rsize = vol->bsize; + return EOK; +} + +static errno_t hr_raid1_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb) +{ + hr_volume_t *vol = bd->srvs->sarg; + + *rnb = vol->data_blkno; + return EOK; +} + static errno_t hr_raid1_check_vol_status(hr_volume_t *vol) { if (vol->status == HR_VOL_ONLINE || @@ -119,18 +216,6 @@ static errno_t hr_raid1_update_vol_status(hr_volume_t *vol) } } -static errno_t hr_raid1_bd_open(bd_srvs_t *bds, bd_srv_t *bd) -{ - DPRINTF("hr_bd_open()\n"); - return EOK; -} - -static errno_t hr_raid1_bd_close(bd_srv_t *bd) -{ - DPRINTF("hr_bd_close()\n"); - return EOK; -} - static void handle_extent_error(hr_volume_t *vol, size_t extent, errno_t rc) { @@ -216,83 +301,5 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, return rc; } -static errno_t hr_raid1_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) -{ - return hr_raid1_bd_op(HR_BD_SYNC, bd, ba, cnt, NULL, NULL, 0); -} - -static errno_t hr_raid1_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, - void *buf, size_t size) -{ - return hr_raid1_bd_op(HR_BD_READ, bd, ba, cnt, buf, NULL, size); -} - -static errno_t hr_raid1_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, - const void *data, size_t size) -{ - return hr_raid1_bd_op(HR_BD_WRITE, bd, ba, cnt, NULL, data, size); -} - -static errno_t hr_raid1_bd_get_block_size(bd_srv_t *bd, size_t *rsize) -{ - hr_volume_t *vol = bd->srvs->sarg; - - *rsize = vol->bsize; - return EOK; -} - -static errno_t hr_raid1_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb) -{ - hr_volume_t *vol = bd->srvs->sarg; - - *rnb = vol->data_blkno; - return EOK; -} - -errno_t hr_raid1_create(hr_volume_t *new_volume) -{ - errno_t rc; - - assert(new_volume->level == HR_LVL_1); - - if (new_volume->dev_no < 2) { - ERR_PRINTF("RAID 1 array needs at least 2 devices\n"); - return EINVAL; - } - - rc = hr_raid1_update_vol_status(new_volume); - if (rc != EOK) - return rc; - - bd_srvs_init(&new_volume->hr_bds); - new_volume->hr_bds.ops = &hr_raid1_bd_ops; - new_volume->hr_bds.sarg = new_volume; - - rc = hr_register_volume(new_volume); - - return rc; -} - -errno_t hr_raid1_init(hr_volume_t *vol) -{ - errno_t rc; - size_t bsize; - uint64_t total_blkno; - - assert(vol->level == HR_LVL_1); - - rc = hr_check_devs(vol, &total_blkno, &bsize); - if (rc != EOK) - return rc; - - vol->nblocks = total_blkno / vol->dev_no; - vol->bsize = bsize; - vol->data_offset = HR_DATA_OFF; - vol->data_blkno = vol->nblocks - vol->data_offset; - vol->strip_size = 0; - - return EOK; -} - /** @} */ diff --git a/uspace/srv/bd/hr/raid4.c b/uspace/srv/bd/hr/raid4.c index e1c1e763b6..b7a92521df 100644 --- a/uspace/srv/bd/hr/raid4.c +++ b/uspace/srv/bd/hr/raid4.c @@ -54,6 +54,20 @@ extern loc_srv_t *hr_srv; +static errno_t hr_raid4_vol_usable(hr_volume_t *); +static ssize_t hr_raid4_get_bad_ext(hr_volume_t *); +static errno_t hr_raid4_update_vol_status(hr_volume_t *); +static void xor(void *, const void *, size_t); +static errno_t hr_raid4_read_degraded(hr_volume_t *, uint64_t, uint64_t, + void *, size_t); +static errno_t hr_raid4_write(hr_volume_t *, uint64_t, aoff64_t, const void *, + size_t); +static errno_t hr_raid4_write_parity(hr_volume_t *, uint64_t, uint64_t, + const void *, size_t); +static errno_t hr_raid4_bd_op(hr_bd_op_type_t, bd_srv_t *, aoff64_t, size_t, + void *, const void *, size_t); + +/* bdops */ static errno_t hr_raid4_bd_open(bd_srvs_t *, bd_srv_t *); static errno_t hr_raid4_bd_close(bd_srv_t *); static errno_t hr_raid4_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, @@ -77,6 +91,97 @@ static bd_ops_t hr_raid4_bd_ops = { .get_num_blocks = hr_raid4_bd_get_num_blocks }; +errno_t hr_raid4_create(hr_volume_t *new_volume) +{ + errno_t rc; + + assert(new_volume->level == HR_LVL_4); + + if (new_volume->dev_no < 3) { + ERR_PRINTF("RAID 4 array needs at least 3 devices"); + return EINVAL; + } + + rc = hr_raid4_update_vol_status(new_volume); + if (rc != EOK) + return rc; + + bd_srvs_init(&new_volume->hr_bds); + new_volume->hr_bds.ops = &hr_raid4_bd_ops; + new_volume->hr_bds.sarg = new_volume; + + rc = hr_register_volume(new_volume); + + return rc; +} + +errno_t hr_raid4_init(hr_volume_t *vol) +{ + errno_t rc; + size_t bsize; + uint64_t total_blkno; + + assert(vol->level == HR_LVL_4); + + rc = hr_check_devs(vol, &total_blkno, &bsize); + if (rc != EOK) + return rc; + + vol->nblocks = total_blkno; + vol->bsize = bsize; + vol->data_offset = HR_DATA_OFF; + vol->data_blkno = vol->nblocks - (vol->data_offset * vol->dev_no) - + (vol->nblocks / vol->dev_no); + vol->strip_size = HR_STRIP_SIZE; + + return EOK; +} + +static errno_t hr_raid4_bd_open(bd_srvs_t *bds, bd_srv_t *bd) +{ + DPRINTF("hr_bd_open()\n"); + return EOK; +} + +static errno_t hr_raid4_bd_close(bd_srv_t *bd) +{ + DPRINTF("hr_bd_close()\n"); + return EOK; +} + +static errno_t hr_raid4_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) +{ + return hr_raid4_bd_op(HR_BD_SYNC, bd, ba, cnt, NULL, NULL, 0); +} + +static errno_t hr_raid4_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, + void *buf, size_t size) +{ + return hr_raid4_bd_op(HR_BD_READ, bd, ba, cnt, buf, NULL, size); +} + +static errno_t hr_raid4_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, + const void *data, size_t size) +{ + return hr_raid4_bd_op(HR_BD_WRITE, bd, ba, cnt, NULL, data, size); +} + +static errno_t hr_raid4_bd_get_block_size(bd_srv_t *bd, size_t *rsize) +{ + hr_volume_t *vol = bd->srvs->sarg; + + *rsize = vol->bsize; + return EOK; +} + +static errno_t hr_raid4_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb) +{ + hr_volume_t *vol = bd->srvs->sarg; + + *rnb = vol->data_blkno; + return EOK; +} + static errno_t hr_raid4_vol_usable(hr_volume_t *vol) { if (vol->status == HR_VOL_ONLINE || @@ -318,18 +423,6 @@ static errno_t hr_raid4_write_parity(hr_volume_t *vol, uint64_t extent, return rc; } -static errno_t hr_raid4_bd_open(bd_srvs_t *bds, bd_srv_t *bd) -{ - DPRINTF("hr_bd_open()\n"); - return EOK; -} - -static errno_t hr_raid4_bd_close(bd_srv_t *bd) -{ - DPRINTF("hr_bd_close()\n"); - return EOK; -} - static errno_t hr_raid4_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, size_t cnt, void *dst, const void *src, size_t size) { @@ -451,84 +544,5 @@ static errno_t hr_raid4_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, return rc; } -static errno_t hr_raid4_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) -{ - return hr_raid4_bd_op(HR_BD_SYNC, bd, ba, cnt, NULL, NULL, 0); -} - -static errno_t hr_raid4_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, - void *buf, size_t size) -{ - return hr_raid4_bd_op(HR_BD_READ, bd, ba, cnt, buf, NULL, size); -} - -static errno_t hr_raid4_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, - const void *data, size_t size) -{ - return hr_raid4_bd_op(HR_BD_WRITE, bd, ba, cnt, NULL, data, size); -} - -static errno_t hr_raid4_bd_get_block_size(bd_srv_t *bd, size_t *rsize) -{ - hr_volume_t *vol = bd->srvs->sarg; - - *rsize = vol->bsize; - return EOK; -} - -static errno_t hr_raid4_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb) -{ - hr_volume_t *vol = bd->srvs->sarg; - - *rnb = vol->data_blkno; - return EOK; -} - -errno_t hr_raid4_create(hr_volume_t *new_volume) -{ - errno_t rc; - - assert(new_volume->level == HR_LVL_4); - - if (new_volume->dev_no < 3) { - ERR_PRINTF("RAID 4 array needs at least 3 devices"); - return EINVAL; - } - - rc = hr_raid4_update_vol_status(new_volume); - if (rc != EOK) - return rc; - - bd_srvs_init(&new_volume->hr_bds); - new_volume->hr_bds.ops = &hr_raid4_bd_ops; - new_volume->hr_bds.sarg = new_volume; - - rc = hr_register_volume(new_volume); - - return rc; -} - -errno_t hr_raid4_init(hr_volume_t *vol) -{ - errno_t rc; - size_t bsize; - uint64_t total_blkno; - - assert(vol->level == HR_LVL_4); - - rc = hr_check_devs(vol, &total_blkno, &bsize); - if (rc != EOK) - return rc; - - vol->nblocks = total_blkno; - vol->bsize = bsize; - vol->data_offset = HR_DATA_OFF; - vol->data_blkno = vol->nblocks - (vol->data_offset * vol->dev_no) - - (vol->nblocks / vol->dev_no); - vol->strip_size = HR_STRIP_SIZE; - - return EOK; -} - /** @} */ diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 69806f864b..7b35e65eab 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -54,6 +54,20 @@ extern loc_srv_t *hr_srv; +static errno_t hr_raid5_vol_usable(hr_volume_t *); +static ssize_t hr_raid5_get_bad_ext(hr_volume_t *); +static errno_t hr_raid5_update_vol_status(hr_volume_t *); +static void xor(void *, const void *, size_t); +static errno_t hr_raid5_read_degraded(hr_volume_t *, uint64_t, uint64_t, + void *, size_t); +static errno_t hr_raid5_write(hr_volume_t *, uint64_t, uint64_t, aoff64_t, + const void *, size_t); +static errno_t hr_raid5_write_parity(hr_volume_t *, uint64_t, uint64_t, + uint64_t, const void *, size_t); +static errno_t hr_raid5_bd_op(hr_bd_op_type_t, bd_srv_t *, aoff64_t, size_t, + void *, const void *, size_t); + +/* bdops */ static errno_t hr_raid5_bd_open(bd_srvs_t *, bd_srv_t *); static errno_t hr_raid5_bd_close(bd_srv_t *); static errno_t hr_raid5_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, @@ -64,9 +78,6 @@ static errno_t hr_raid5_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, static errno_t hr_raid5_bd_get_block_size(bd_srv_t *, size_t *); static errno_t hr_raid5_bd_get_num_blocks(bd_srv_t *, aoff64_t *); -static errno_t hr_raid5_write_parity(hr_volume_t *, uint64_t, uint64_t, - uint64_t, const void *, size_t); - static bd_ops_t hr_raid5_bd_ops = { .open = hr_raid5_bd_open, .close = hr_raid5_bd_close, @@ -77,6 +88,97 @@ static bd_ops_t hr_raid5_bd_ops = { .get_num_blocks = hr_raid5_bd_get_num_blocks }; +errno_t hr_raid5_create(hr_volume_t *new_volume) +{ + errno_t rc; + + assert(new_volume->level == HR_LVL_5); + + if (new_volume->dev_no < 3) { + ERR_PRINTF("RAID 5 array needs at least 3 devices"); + return EINVAL; + } + + rc = hr_raid5_update_vol_status(new_volume); + if (rc != EOK) + return rc; + + bd_srvs_init(&new_volume->hr_bds); + new_volume->hr_bds.ops = &hr_raid5_bd_ops; + new_volume->hr_bds.sarg = new_volume; + + rc = hr_register_volume(new_volume); + + return rc; +} + +errno_t hr_raid5_init(hr_volume_t *vol) +{ + errno_t rc; + size_t bsize; + uint64_t total_blkno; + + assert(vol->level == HR_LVL_5); + + rc = hr_check_devs(vol, &total_blkno, &bsize); + if (rc != EOK) + return rc; + + vol->nblocks = total_blkno; + vol->bsize = bsize; + vol->data_offset = HR_DATA_OFF; + vol->data_blkno = vol->nblocks - (vol->data_offset * vol->dev_no) - + (vol->nblocks / vol->dev_no); + vol->strip_size = HR_STRIP_SIZE; + + return EOK; +} + +static errno_t hr_raid5_bd_open(bd_srvs_t *bds, bd_srv_t *bd) +{ + DPRINTF("hr_bd_open()\n"); + return EOK; +} + +static errno_t hr_raid5_bd_close(bd_srv_t *bd) +{ + DPRINTF("hr_bd_close()\n"); + return EOK; +} + +static errno_t hr_raid5_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) +{ + return hr_raid5_bd_op(HR_BD_SYNC, bd, ba, cnt, NULL, NULL, 0); +} + +static errno_t hr_raid5_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, + void *buf, size_t size) +{ + return hr_raid5_bd_op(HR_BD_READ, bd, ba, cnt, buf, NULL, size); +} + +static errno_t hr_raid5_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, + const void *data, size_t size) +{ + return hr_raid5_bd_op(HR_BD_WRITE, bd, ba, cnt, NULL, data, size); +} + +static errno_t hr_raid5_bd_get_block_size(bd_srv_t *bd, size_t *rsize) +{ + hr_volume_t *vol = bd->srvs->sarg; + + *rsize = vol->bsize; + return EOK; +} + +static errno_t hr_raid5_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb) +{ + hr_volume_t *vol = bd->srvs->sarg; + + *rnb = vol->data_blkno; + return EOK; +} + static errno_t hr_raid5_vol_usable(hr_volume_t *vol) { if (vol->status == HR_VOL_ONLINE || @@ -318,18 +420,6 @@ static errno_t hr_raid5_write_parity(hr_volume_t *vol, uint64_t p_extent, return rc; } -static errno_t hr_raid5_bd_open(bd_srvs_t *bds, bd_srv_t *bd) -{ - DPRINTF("hr_bd_open()\n"); - return EOK; -} - -static errno_t hr_raid5_bd_close(bd_srv_t *bd) -{ - DPRINTF("hr_bd_close()\n"); - return EOK; -} - static errno_t hr_raid5_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, size_t cnt, void *dst, const void *src, size_t size) { @@ -460,84 +550,5 @@ static errno_t hr_raid5_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, return rc; } -static errno_t hr_raid5_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) -{ - return hr_raid5_bd_op(HR_BD_SYNC, bd, ba, cnt, NULL, NULL, 0); -} - -static errno_t hr_raid5_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, - void *buf, size_t size) -{ - return hr_raid5_bd_op(HR_BD_READ, bd, ba, cnt, buf, NULL, size); -} - -static errno_t hr_raid5_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, - const void *data, size_t size) -{ - return hr_raid5_bd_op(HR_BD_WRITE, bd, ba, cnt, NULL, data, size); -} - -static errno_t hr_raid5_bd_get_block_size(bd_srv_t *bd, size_t *rsize) -{ - hr_volume_t *vol = bd->srvs->sarg; - - *rsize = vol->bsize; - return EOK; -} - -static errno_t hr_raid5_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb) -{ - hr_volume_t *vol = bd->srvs->sarg; - - *rnb = vol->data_blkno; - return EOK; -} - -errno_t hr_raid5_create(hr_volume_t *new_volume) -{ - errno_t rc; - - assert(new_volume->level == HR_LVL_5); - - if (new_volume->dev_no < 3) { - ERR_PRINTF("RAID 5 array needs at least 3 devices"); - return EINVAL; - } - - rc = hr_raid5_update_vol_status(new_volume); - if (rc != EOK) - return rc; - - bd_srvs_init(&new_volume->hr_bds); - new_volume->hr_bds.ops = &hr_raid5_bd_ops; - new_volume->hr_bds.sarg = new_volume; - - rc = hr_register_volume(new_volume); - - return rc; -} - -errno_t hr_raid5_init(hr_volume_t *vol) -{ - errno_t rc; - size_t bsize; - uint64_t total_blkno; - - assert(vol->level == HR_LVL_5); - - rc = hr_check_devs(vol, &total_blkno, &bsize); - if (rc != EOK) - return rc; - - vol->nblocks = total_blkno; - vol->bsize = bsize; - vol->data_offset = HR_DATA_OFF; - vol->data_blkno = vol->nblocks - (vol->data_offset * vol->dev_no) - - (vol->nblocks / vol->dev_no); - vol->strip_size = HR_STRIP_SIZE; - - return EOK; -} - /** @} */ From b235c674e609e25641c699d43521c045c825a247 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 15 Nov 2024 17:30:29 +0100 Subject: [PATCH 066/324] hr: use shorthand vol for volume --- uspace/srv/bd/hr/hr.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 730c7d96ff..bdfb7a45b3 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -64,10 +64,10 @@ static hr_volume_t *hr_get_volume(service_id_t svc_id) DPRINTF("hr_get_volume(): (%" PRIun ")\n", svc_id); fibril_mutex_lock(&hr_volumes_lock); - list_foreach(hr_volumes, lvolumes, hr_volume_t, volume) { - if (volume->svc_id == svc_id) { + list_foreach(hr_volumes, lvolumes, hr_volume_t, vol) { + if (vol->svc_id == svc_id) { fibril_mutex_unlock(&hr_volumes_lock); - return volume; + return vol; } } @@ -80,11 +80,11 @@ static errno_t hr_remove_volume(service_id_t svc_id) DPRINTF("hr_remove_volume(): (%" PRIun ")\n", svc_id); fibril_mutex_lock(&hr_volumes_lock); - list_foreach(hr_volumes, lvolumes, hr_volume_t, volume) { - if (volume->svc_id == svc_id) { - hr_fini_devs(volume); - list_remove(&volume->lvolumes); - free(volume); + list_foreach(hr_volumes, lvolumes, hr_volume_t, vol) { + if (vol->svc_id == svc_id) { + hr_fini_devs(vol); + list_remove(&vol->lvolumes); + free(vol); fibril_mutex_unlock(&hr_volumes_lock); return EOK; } @@ -309,17 +309,17 @@ static void hr_print_status_srv(ipc_call_t *icall) if (rc != EOK) goto error; - list_foreach(hr_volumes, lvolumes, hr_volume_t, volume) { - memcpy(info.extents, volume->extents, + list_foreach(hr_volumes, lvolumes, hr_volume_t, vol) { + memcpy(info.extents, vol->extents, sizeof(hr_extent_t) * HR_MAXDEVS); - info.svc_id = volume->svc_id; - info.extent_no = volume->dev_no; - info.level = volume->level; + info.svc_id = vol->svc_id; + info.extent_no = vol->dev_no; + info.level = vol->level; /* print usable number of blocks */ - info.nblocks = volume->data_blkno; - info.strip_size = volume->strip_size; - info.bsize = volume->bsize; - info.status = volume->status; + info.nblocks = vol->data_blkno; + info.strip_size = vol->strip_size; + info.bsize = vol->bsize; + info.status = vol->status; if (!async_data_read_receive(&call, &size)) { rc = EREFUSED; From 64eba5747bd4159f28f1d592d1ea5cd573899d2f Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 15 Nov 2024 18:39:24 +0100 Subject: [PATCH 067/324] hrctl: fix memory leaks --- uspace/app/hrctl/hrctl.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index 6949ed3d38..460c1cc646 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -251,8 +251,10 @@ int main(int argc, char **argv) switch (c) { case 'h': usage(); + free(cfg); return 0; case 's': + free(cfg); rc = hr_print_status(); if (rc != EOK) return 1; @@ -262,6 +264,7 @@ int main(int argc, char **argv) rc = load_config(optarg, cfg); if (rc != EOK) { printf("hrctl: failed to load config\n"); + free(cfg); return 1; } create = true; @@ -269,6 +272,7 @@ int main(int argc, char **argv) case 'c': if (str_size(optarg) > sizeof(cfg->devname) - 1) { printf("hrctl: device name too long\n"); + free(cfg); return 1; } str_cpy(cfg->devname, sizeof(cfg->devname), optarg); @@ -278,6 +282,7 @@ int main(int argc, char **argv) rc = load_config(optarg, cfg); if (rc != EOK) { printf("hrctl: failed to load config\n"); + free(cfg); return 1; } assemble = true; @@ -285,6 +290,7 @@ int main(int argc, char **argv) case 'a': if (str_size(optarg) > sizeof(cfg->devname) - 1) { printf("hrctl: device name too long\n"); + free(cfg); return 1; } str_cpy(cfg->devname, sizeof(cfg->devname), optarg); @@ -333,8 +339,10 @@ int main(int argc, char **argv) if ((int) cfg->dev_no + optind != argc) goto bad; rc = fill_config_devs(argc, argv, optind, cfg); - if (rc != EOK) + if (rc != EOK) { + free(cfg); return 1; + } break; } } @@ -345,17 +353,17 @@ int main(int argc, char **argv) if (create && cfg->level == HR_LVL_UNKNOWN) { printf("hrctl: invalid level, exiting\n"); - return 1; + goto bad; } if (cfg->dev_no > HR_MAXDEVS) { printf("hrctl: too many devices, exiting\n"); - return 1; + goto bad; } if (cfg->dev_no == 0) { printf("hrctl: invalid number of devices, exiting\n"); - return 1; + goto bad; } rc = hr_sess_init(&hr); From dfa23139b238a19fdf1f2f5cb9a5e43a78b00d7e Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 15 Nov 2024 22:21:29 +0100 Subject: [PATCH 068/324] hr: rename HR_MAXDEVS -> HR_MAX_EXTENTS --- uspace/app/hrctl/hrctl.c | 2 +- uspace/lib/device/include/hr.h | 6 +++--- uspace/srv/bd/hr/hr.c | 2 +- uspace/srv/bd/hr/superblock.c | 4 ++-- uspace/srv/bd/hr/var.h | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index 460c1cc646..cdd6ff61bc 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -356,7 +356,7 @@ int main(int argc, char **argv) goto bad; } - if (cfg->dev_no > HR_MAXDEVS) { + if (cfg->dev_no > HR_MAX_EXTENTS) { printf("hrctl: too many devices, exiting\n"); goto bad; } diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index 264d98e683..eaa0b49957 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -41,7 +41,7 @@ #include /* for now */ -#define HR_MAXDEVS 4 +#define HR_MAX_EXTENTS 4 #define HR_DEVNAME_LEN 32 @@ -71,7 +71,7 @@ typedef struct hr { typedef struct hr_config { char devname[HR_DEVNAME_LEN]; - service_id_t devs[HR_MAXDEVS]; + service_id_t devs[HR_MAX_EXTENTS]; size_t dev_no; hr_level_t level; } hr_config_t; @@ -82,7 +82,7 @@ typedef struct hr_extent { } hr_extent_t; typedef struct hr_vol_info { - hr_extent_t extents[HR_MAXDEVS]; + hr_extent_t extents[HR_MAX_EXTENTS]; size_t extent_no; service_id_t svc_id; hr_level_t level; diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index bdfb7a45b3..ecd8810803 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -311,7 +311,7 @@ static void hr_print_status_srv(ipc_call_t *icall) list_foreach(hr_volumes, lvolumes, hr_volume_t, vol) { memcpy(info.extents, vol->extents, - sizeof(hr_extent_t) * HR_MAXDEVS); + sizeof(hr_extent_t) * HR_MAX_EXTENTS); info.svc_id = vol->svc_id; info.extent_no = vol->dev_no; info.level = vol->level; diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index b77ffe75c1..3945daa9f9 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -130,11 +130,11 @@ errno_t hr_fill_vol_from_meta(hr_volume_t *vol) if (metadata == NULL) return ENOMEM; - service_id_t cfg_svc_id_order[HR_MAXDEVS] = { 0 }; + service_id_t cfg_svc_id_order[HR_MAX_EXTENTS] = { 0 }; for (size_t i = 0; i < vol->dev_no; i++) cfg_svc_id_order[i] = vol->extents[i].svc_id; - int32_t md_order[HR_MAXDEVS] = { 0 }; + int32_t md_order[HR_MAX_EXTENTS] = { 0 }; for (size_t i = 0; i < vol->dev_no; i++) { if (cfg_svc_id_order[i] == 0) { md_order[i] = -1; diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index 00d4a96e2d..c973619012 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -57,7 +57,7 @@ typedef struct hr_volume { link_t lvolumes; fibril_mutex_t lock; char devname[HR_DEVNAME_LEN]; - hr_extent_t extents[HR_MAXDEVS]; + hr_extent_t extents[HR_MAX_EXTENTS]; uint64_t nblocks; uint64_t data_blkno; uint32_t data_offset; /* in blocks */ From d199a6f07126d0468e442d3bfb04a41963b136b1 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 15 Nov 2024 22:32:20 +0100 Subject: [PATCH 069/324] hr: DPRINTF, ERR_PRINTF -> HR_DEBUG, HR_ERROR Also add HR_WARN for warning level. --- uspace/srv/bd/hr/hr.c | 31 +++++++++++++++---------------- uspace/srv/bd/hr/raid0.c | 8 ++++---- uspace/srv/bd/hr/raid1.c | 12 ++++++------ uspace/srv/bd/hr/raid4.c | 12 ++++++------ uspace/srv/bd/hr/raid5.c | 12 ++++++------ uspace/srv/bd/hr/superblock.c | 15 +++++++-------- uspace/srv/bd/hr/util.c | 29 ++++++++++++++--------------- uspace/srv/bd/hr/util.h | 7 +++++-- 8 files changed, 63 insertions(+), 63 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index ecd8810803..c4472cfea4 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -61,7 +61,7 @@ static service_id_t ctl_sid; static hr_volume_t *hr_get_volume(service_id_t svc_id) { - DPRINTF("hr_get_volume(): (%" PRIun ")\n", svc_id); + HR_DEBUG("hr_get_volume(): (%" PRIun ")\n", svc_id); fibril_mutex_lock(&hr_volumes_lock); list_foreach(hr_volumes, lvolumes, hr_volume_t, vol) { @@ -77,7 +77,7 @@ static hr_volume_t *hr_get_volume(service_id_t svc_id) static errno_t hr_remove_volume(service_id_t svc_id) { - DPRINTF("hr_remove_volume(): (%" PRIun ")\n", svc_id); + HR_DEBUG("hr_remove_volume(): (%" PRIun ")\n", svc_id); fibril_mutex_lock(&hr_volumes_lock); list_foreach(hr_volumes, lvolumes, hr_volume_t, vol) { @@ -96,7 +96,7 @@ static errno_t hr_remove_volume(service_id_t svc_id) static void hr_create_srv(ipc_call_t *icall, bool assemble) { - DPRINTF("hr_create_srv()\n"); + HR_DEBUG("hr_create_srv()\n"); errno_t rc; size_t i, size; @@ -138,7 +138,7 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) if (!assemble) { for (i = 0; i < cfg->dev_no; i++) { if (cfg->devs[i] == 0) { - ERR_PRINTF("missing device provided for array " + HR_ERROR("missing device provided for array " "creation, aborting"); free(cfg); async_answer_0(icall, EINVAL); @@ -162,8 +162,7 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) if (assemble) { if (cfg->level != HR_LVL_UNKNOWN) - log_msg(LOG_DEFAULT, LVL_WARN, - "level manually set when assembling, ingoring"); + HR_WARN("level manually set when assembling, ingoring"); new_volume->level = HR_LVL_UNKNOWN; } @@ -204,7 +203,7 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) new_volume->hr_ops.init = hr_raid5_init; break; default: - ERR_PRINTF("unkown level: %d, aborting\n", new_volume->level); + HR_ERROR("unkown level: %d, aborting\n", new_volume->level); rc = EINVAL; goto error; } @@ -230,10 +229,10 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) fibril_mutex_unlock(&hr_volumes_lock); if (assemble) { - DPRINTF("assembled volume \"%s\" (%" PRIun ")\n", + HR_DEBUG("assembled volume \"%s\" (%" PRIun ")\n", new_volume->devname, new_volume->svc_id); } else { - DPRINTF("created volume \"%s\" (%" PRIun ")\n", + HR_DEBUG("created volume \"%s\" (%" PRIun ")\n", new_volume->devname, new_volume->svc_id); } @@ -249,7 +248,7 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) static void hr_stop_srv(ipc_call_t *icall) { - DPRINTF("hr_stop_srv()\n"); + HR_DEBUG("hr_stop_srv()\n"); errno_t rc = EOK; service_id_t svc_id; @@ -283,7 +282,7 @@ static void hr_stop_srv(ipc_call_t *icall) static void hr_print_status_srv(ipc_call_t *icall) { - DPRINTF("hr_status_srv()\n"); + HR_DEBUG("hr_status_srv()\n"); errno_t rc; size_t vol_cnt = 0; @@ -347,7 +346,7 @@ static void hr_print_status_srv(ipc_call_t *icall) static void hr_ctl_conn(ipc_call_t *icall, void *arg) { - DPRINTF("hr_ctl_conn()\n"); + HR_DEBUG("hr_ctl_conn()\n"); async_accept_0(icall); @@ -382,7 +381,7 @@ static void hr_ctl_conn(ipc_call_t *icall, void *arg) static void hr_client_conn(ipc_call_t *icall, void *arg) { - DPRINTF("hr_client_conn()\n"); + HR_DEBUG("hr_client_conn()\n"); hr_volume_t *vol; @@ -391,7 +390,7 @@ static void hr_client_conn(ipc_call_t *icall, void *arg) if (svc_id == ctl_sid) { hr_ctl_conn(icall, arg); } else { - DPRINTF("bd_conn()\n"); + HR_DEBUG("bd_conn()\n"); vol = hr_get_volume(svc_id); if (vol == NULL) async_answer_0(icall, EINVAL); @@ -418,13 +417,13 @@ int main(int argc, char **argv) rc = loc_server_register(NAME, &hr_srv); if (rc != EOK) { - ERR_PRINTF("failed registering server: %s", str_error(rc)); + HR_ERROR("failed registering server: %s", str_error(rc)); return EEXIST; } rc = loc_service_register(hr_srv, SERVICE_NAME_HR, &ctl_sid); if (rc != EOK) { - ERR_PRINTF("failed registering service: %s", str_error(rc)); + HR_ERROR("failed registering service: %s", str_error(rc)); return EEXIST; } diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index dc80df92d7..ce04e9bc9b 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -86,7 +86,7 @@ errno_t hr_raid0_create(hr_volume_t *new_volume) assert(new_volume->level == HR_LVL_0); if (new_volume->dev_no < 2) { - ERR_PRINTF("RAID 0 array needs at least 2 devices"); + HR_ERROR("RAID 0 array needs at least 2 devices\n"); return EINVAL; } @@ -126,13 +126,13 @@ errno_t hr_raid0_init(hr_volume_t *vol) static errno_t hr_raid0_bd_open(bd_srvs_t *bds, bd_srv_t *bd) { - DPRINTF("hr_bd_open()\n"); + HR_DEBUG("hr_bd_open()\n"); return EOK; } static errno_t hr_raid0_bd_close(bd_srv_t *bd) { - DPRINTF("hr_bd_close()\n"); + HR_DEBUG("hr_bd_close()\n"); return EOK; } @@ -184,7 +184,7 @@ static errno_t hr_raid0_update_vol_status(hr_volume_t *vol) { for (size_t i = 0; i < vol->dev_no; i++) { if (vol->extents[i].status != HR_EXT_ONLINE) { - ERR_PRINTF("RAID 0 needs all extents to be ONLINE, " + HR_WARN("RAID 0 needs all extents to be ONLINE, " "marking \"%s\" (%lu) as FAULTY", vol->devname, vol->svc_id); vol->status = HR_VOL_FAULTY; diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index d62c2489b5..cd12120dca 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -86,7 +86,7 @@ errno_t hr_raid1_create(hr_volume_t *new_volume) assert(new_volume->level == HR_LVL_1); if (new_volume->dev_no < 2) { - ERR_PRINTF("RAID 1 array needs at least 2 devices\n"); + HR_ERROR("RAID 1 array needs at least 2 devices\n"); return EINVAL; } @@ -126,13 +126,13 @@ errno_t hr_raid1_init(hr_volume_t *vol) static errno_t hr_raid1_bd_open(bd_srvs_t *bds, bd_srv_t *bd) { - DPRINTF("hr_bd_open()\n"); + HR_DEBUG("hr_bd_open()\n"); return EOK; } static errno_t hr_raid1_bd_close(bd_srv_t *bd) { - DPRINTF("hr_bd_close()\n"); + HR_DEBUG("hr_bd_close()\n"); return EOK; } @@ -191,7 +191,7 @@ static errno_t hr_raid1_update_vol_status(hr_volume_t *vol) if (healthy == 0) { if (old_state != HR_VOL_FAULTY) { - ERR_PRINTF("RAID 1 needs at least 1 extent to be" + HR_WARN("RAID 1 needs at least 1 extent to be" "ONLINE, marking \"%s\" (%lu) volume as FAULTY", vol->devname, vol->svc_id); vol->status = HR_VOL_FAULTY; @@ -199,7 +199,7 @@ static errno_t hr_raid1_update_vol_status(hr_volume_t *vol) return EINVAL; } else if (healthy < vol->dev_no) { if (old_state != HR_VOL_DEGRADED) { - ERR_PRINTF("RAID 1 array \"%s\" (%lu) has some " + HR_WARN("RAID 1 array \"%s\" (%lu) has some " "inactive extent(s), marking volume as DEGRADED", vol->devname, vol->svc_id); vol->status = HR_VOL_DEGRADED; @@ -207,7 +207,7 @@ static errno_t hr_raid1_update_vol_status(hr_volume_t *vol) return EOK; } else { if (old_state != HR_VOL_ONLINE) { - DPRINTF("RAID 1 array \"%s\" (%lu) has all extents " + HR_WARN("RAID 1 array \"%s\" (%lu) has all extents " "active, marking volume as ONLINE", vol->devname, vol->svc_id); vol->status = HR_VOL_ONLINE; diff --git a/uspace/srv/bd/hr/raid4.c b/uspace/srv/bd/hr/raid4.c index b7a92521df..2d6b45d791 100644 --- a/uspace/srv/bd/hr/raid4.c +++ b/uspace/srv/bd/hr/raid4.c @@ -98,7 +98,7 @@ errno_t hr_raid4_create(hr_volume_t *new_volume) assert(new_volume->level == HR_LVL_4); if (new_volume->dev_no < 3) { - ERR_PRINTF("RAID 4 array needs at least 3 devices"); + HR_ERROR("RAID 4 array needs at least 3 devices\n"); return EINVAL; } @@ -139,13 +139,13 @@ errno_t hr_raid4_init(hr_volume_t *vol) static errno_t hr_raid4_bd_open(bd_srvs_t *bds, bd_srv_t *bd) { - DPRINTF("hr_bd_open()\n"); + HR_DEBUG("hr_bd_open()\n"); return EOK; } static errno_t hr_raid4_bd_close(bd_srv_t *bd) { - DPRINTF("hr_bd_close()\n"); + HR_DEBUG("hr_bd_close()\n"); return EOK; } @@ -213,7 +213,7 @@ static errno_t hr_raid4_update_vol_status(hr_volume_t *vol) switch (bad) { case 0: if (old_state != HR_VOL_ONLINE) { - DPRINTF("RAID 4 has all extents online, " + HR_WARN("RAID 4 has all extents online, " "marking \"%s\" (%lu) as ONLINE", vol->devname, vol->svc_id); vol->status = HR_VOL_ONLINE; @@ -221,7 +221,7 @@ static errno_t hr_raid4_update_vol_status(hr_volume_t *vol) return EOK; case 1: if (old_state != HR_VOL_DEGRADED) { - ERR_PRINTF("RAID 4 array \"%s\" (%lu) has 1 extent " + HR_WARN("RAID 4 array \"%s\" (%lu) has 1 extent " "inactive, marking as DEGRADED", vol->devname, vol->svc_id); vol->status = HR_VOL_DEGRADED; @@ -229,7 +229,7 @@ static errno_t hr_raid4_update_vol_status(hr_volume_t *vol) return EOK; default: if (old_state != HR_VOL_FAULTY) { - ERR_PRINTF("RAID 4 array \"%s\" (%lu) has more " + HR_WARN("RAID 4 array \"%s\" (%lu) has more " "than one 1 extent inactive, marking as FAULTY", vol->devname, vol->svc_id); vol->status = HR_VOL_FAULTY; diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 7b35e65eab..62e2d49207 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -95,7 +95,7 @@ errno_t hr_raid5_create(hr_volume_t *new_volume) assert(new_volume->level == HR_LVL_5); if (new_volume->dev_no < 3) { - ERR_PRINTF("RAID 5 array needs at least 3 devices"); + HR_ERROR("RAID 5 array needs at least 3 devices\n"); return EINVAL; } @@ -136,13 +136,13 @@ errno_t hr_raid5_init(hr_volume_t *vol) static errno_t hr_raid5_bd_open(bd_srvs_t *bds, bd_srv_t *bd) { - DPRINTF("hr_bd_open()\n"); + HR_DEBUG("hr_bd_open()\n"); return EOK; } static errno_t hr_raid5_bd_close(bd_srv_t *bd) { - DPRINTF("hr_bd_close()\n"); + HR_DEBUG("hr_bd_close()\n"); return EOK; } @@ -210,7 +210,7 @@ static errno_t hr_raid5_update_vol_status(hr_volume_t *vol) switch (bad) { case 0: if (old_state != HR_VOL_ONLINE) { - DPRINTF("RAID 5 has all extents online, " + HR_WARN("RAID 5 has all extents online, " "marking \"%s\" (%lu) as ONLINE", vol->devname, vol->svc_id); vol->status = HR_VOL_ONLINE; @@ -218,7 +218,7 @@ static errno_t hr_raid5_update_vol_status(hr_volume_t *vol) return EOK; case 1: if (old_state != HR_VOL_DEGRADED) { - ERR_PRINTF("RAID 5 array \"%s\" (%lu) has 1 extent " + HR_WARN("RAID 5 array \"%s\" (%lu) has 1 extent " "inactive, marking as DEGRADED", vol->devname, vol->svc_id); vol->status = HR_VOL_DEGRADED; @@ -226,7 +226,7 @@ static errno_t hr_raid5_update_vol_status(hr_volume_t *vol) return EOK; default: if (old_state != HR_VOL_FAULTY) { - ERR_PRINTF("RAID 5 array \"%s\" (%lu) has more " + HR_WARN("RAID 5 array \"%s\" (%lu) has more " "than one 1 extent inactive, marking as FAULTY", vol->devname, vol->svc_id); vol->status = HR_VOL_FAULTY; diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index 3945daa9f9..599bfc2b10 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -53,7 +53,7 @@ static errno_t read_metadata(service_id_t, hr_metadata_t *); errno_t hr_write_meta_to_vol(hr_volume_t *vol) { - DPRINTF("hr_write_meta_to_vol()\n"); + HR_DEBUG("hr_write_meta_to_vol()\n"); errno_t rc; size_t i; @@ -70,11 +70,11 @@ errno_t hr_write_meta_to_vol(hr_volume_t *vol) meta_blkno *= vol->dev_no; if (vol->nblocks < meta_blkno) { - ERR_PRINTF("not enough blocks to write metadat\n"); + HR_ERROR("not enough blocks to write metadat\n"); rc = EINVAL; goto error; } else if (vol->nblocks == meta_blkno) { - ERR_PRINTF("there would be zero data blocks after writing " + HR_ERROR("there would be zero data blocks after writing " "metadata, aborting"); rc = EINVAL; goto error; @@ -113,7 +113,7 @@ errno_t hr_write_meta_to_vol(hr_volume_t *vol) static errno_t validate_meta(hr_metadata_t *md) { if (uint64_t_le2host(md->magic) != HR_MAGIC) { - ERR_PRINTF("invalid magic\n"); + HR_ERROR("invalid magic\n"); return EINVAL; } return EOK; @@ -121,7 +121,7 @@ static errno_t validate_meta(hr_metadata_t *md) errno_t hr_fill_vol_from_meta(hr_volume_t *vol) { - DPRINTF("hr_get_vol_from_meta()\n"); + HR_DEBUG("hr_get_vol_from_meta()\n"); errno_t rc; hr_metadata_t *metadata; @@ -169,7 +169,7 @@ errno_t hr_fill_vol_from_meta(hr_volume_t *vol) */ if (vol->dev_no != uint32_t_le2host(metadata->extent_no)) { - ERR_PRINTF("number of divices in array differ: specified %zu, " + HR_ERROR("number of divices in array differ: specified %zu, " "metadata states %u", vol->dev_no, uint32_t_le2host(metadata->extent_no)); rc = EINVAL; @@ -183,8 +183,7 @@ errno_t hr_fill_vol_from_meta(hr_volume_t *vol) vol->strip_size = uint32_t_le2host(metadata->strip_size); if (str_cmp(metadata->devname, vol->devname) != 0) { - log_msg(LOG_DEFAULT, LVL_WARN, - "devname on metadata (%s) and config (%s) differ, " + HR_WARN("devname on metadata (%s) and config (%s) differ, " "using config", metadata->devname, vol->devname); } end: diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 29abf3bacb..465a178b9b 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -49,7 +49,7 @@ extern loc_srv_t *hr_srv; errno_t hr_init_devs(hr_volume_t *vol) { - DPRINTF("hr_init_devs()\n"); + HR_DEBUG("hr_init_devs()\n"); errno_t rc; size_t i; @@ -62,13 +62,13 @@ errno_t hr_init_devs(hr_volume_t *vol) continue; } - DPRINTF("hr_init_devs(): block_init() on (%lu)\n", + HR_DEBUG("hr_init_devs(): block_init() on (%lu)\n", extent->svc_id); rc = block_init(extent->svc_id); extent->status = HR_EXT_ONLINE; if (rc != EOK) { - ERR_PRINTF("hr_init_devs(): initing (%lu) failed, " + HR_ERROR("hr_init_devs(): initing (%lu) failed, " "aborting\n", extent->svc_id); break; } @@ -79,13 +79,13 @@ errno_t hr_init_devs(hr_volume_t *vol) void hr_fini_devs(hr_volume_t *vol) { - DPRINTF("hr_fini_devs()\n"); + HR_DEBUG("hr_fini_devs()\n"); size_t i; for (i = 0; i < vol->dev_no; i++) { if (vol->extents[i].status != HR_EXT_MISSING) { - DPRINTF("hr_fini_devs(): block_fini() on (%lu)\n", + HR_DEBUG("hr_fini_devs(): block_fini() on (%lu)\n", vol->extents[i].svc_id); block_fini(vol->extents[i].svc_id); } @@ -94,7 +94,7 @@ void hr_fini_devs(hr_volume_t *vol) errno_t hr_register_volume(hr_volume_t *vol) { - DPRINTF("hr_register_volume()\n"); + HR_DEBUG("hr_register_volume()\n"); errno_t rc; service_id_t new_id; @@ -107,21 +107,21 @@ errno_t hr_register_volume(hr_volume_t *vol) rc = loc_service_register(hr_srv, fullname, &new_id); if (rc != EOK) { - ERR_PRINTF("unable to register device \"%s\": %s\n", + HR_ERROR("unable to register device \"%s\": %s\n", fullname, str_error(rc)); goto error; } rc = loc_category_get_id("raid", &cat_id, IPC_FLAG_BLOCKING); if (rc != EOK) { - ERR_PRINTF("failed resolving category \"raid\": %s\n", + HR_ERROR("failed resolving category \"raid\": %s\n", str_error(rc)); goto error; } rc = loc_service_add_to_cat(hr_srv, new_id, cat_id); if (rc != EOK) { - ERR_PRINTF("failed adding \"%s\" to category \"raid\": %s\n", + HR_ERROR("failed adding \"%s\" to category \"raid\": %s\n", fullname, str_error(rc)); goto error; } @@ -135,7 +135,7 @@ errno_t hr_register_volume(hr_volume_t *vol) errno_t hr_check_devs(hr_volume_t *vol, uint64_t *rblkno, size_t *rbsize) { - DPRINTF("hr_check_devs()\n"); + HR_DEBUG("hr_check_devs()\n"); errno_t rc; size_t i, bsize; @@ -153,7 +153,7 @@ errno_t hr_check_devs(hr_volume_t *vol, uint64_t *rblkno, size_t *rbsize) if (rc != EOK) goto error; if (last_nblocks != 0 && nblocks != last_nblocks) { - ERR_PRINTF("number of blocks differs\n"); + HR_ERROR("number of blocks differs\n"); rc = EINVAL; goto error; } @@ -170,7 +170,7 @@ errno_t hr_check_devs(hr_volume_t *vol, uint64_t *rblkno, size_t *rbsize) if (rc != EOK) goto error; if (last_bsize != 0 && bsize != last_bsize) { - ERR_PRINTF("block sizes differ\n"); + HR_ERROR("block sizes differ\n"); rc = EINVAL; goto error; } @@ -179,7 +179,7 @@ errno_t hr_check_devs(hr_volume_t *vol, uint64_t *rblkno, size_t *rbsize) } if ((bsize % 512) != 0) { - ERR_PRINTF("block size not multiple of 512\n"); + HR_ERROR("block size not multiple of 512\n"); return EINVAL; } @@ -205,8 +205,7 @@ void hr_add_ba_offset(hr_volume_t *vol, uint64_t *ba) void hr_update_ext_status(hr_volume_t *vol, uint64_t extent, hr_ext_status_t s) { - log_msg(LOG_DEFAULT, LVL_WARN, - "vol %s, changing extent: %lu, to status: %s", + HR_WARN("vol %s, changing extent: %lu, to status: %s", vol->devname, extent, hr_get_ext_status_msg(s)); vol->extents[extent].status = s; } diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index faff0ff8a3..6ba9ab3807 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -40,10 +40,13 @@ #include "var.h" -#define DPRINTF(format, ...) \ +#define HR_DEBUG(format, ...) \ log_msg(LOG_DEFAULT, LVL_DEBUG, format, ##__VA_ARGS__) -#define ERR_PRINTF(format, ...) \ +#define HR_WARN(format, ...) \ + log_msg(LOG_DEFAULT, LVL_WARN, format, ##__VA_ARGS__) + +#define HR_ERROR(format, ...) \ log_msg(LOG_DEFAULT, LVL_ERROR, format, ##__VA_ARGS__) extern errno_t hr_init_devs(hr_volume_t *); From 7b359f53c55874a1b2e9ae92ad9f3b5c167cf609 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 15 Nov 2024 22:45:31 +0100 Subject: [PATCH 070/324] hr: status/state event function for each RAID --- uspace/srv/bd/hr/hr.c | 6 ++++++ uspace/srv/bd/hr/raid0.c | 7 +++++++ uspace/srv/bd/hr/raid1.c | 7 +++++++ uspace/srv/bd/hr/raid4.c | 7 +++++++ uspace/srv/bd/hr/raid5.c | 7 +++++++ uspace/srv/bd/hr/var.h | 6 ++++++ 6 files changed, 40 insertions(+) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index c4472cfea4..f295afb211 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -189,18 +189,22 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) case HR_LVL_1: new_volume->hr_ops.create = hr_raid1_create; new_volume->hr_ops.init = hr_raid1_init; + new_volume->hr_ops.status_event = hr_raid1_status_event; break; case HR_LVL_0: new_volume->hr_ops.create = hr_raid0_create; new_volume->hr_ops.init = hr_raid0_init; + new_volume->hr_ops.status_event = hr_raid0_status_event; break; case HR_LVL_4: new_volume->hr_ops.create = hr_raid4_create; new_volume->hr_ops.init = hr_raid4_init; + new_volume->hr_ops.status_event = hr_raid4_status_event; break; case HR_LVL_5: new_volume->hr_ops.create = hr_raid5_create; new_volume->hr_ops.init = hr_raid5_init; + new_volume->hr_ops.status_event = hr_raid5_status_event; break; default: HR_ERROR("unkown level: %d, aborting\n", new_volume->level); @@ -276,6 +280,8 @@ static void hr_stop_srv(ipc_call_t *icall) fibril_mutex_lock(&vol->lock); hr_update_ext_status(vol, fail_extent, HR_EXT_FAILED); fibril_mutex_unlock(&vol->lock); + + vol->hr_ops.status_event(vol); } async_answer_0(icall, rc); } diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index ce04e9bc9b..1101b25610 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -124,6 +124,13 @@ errno_t hr_raid0_init(hr_volume_t *vol) return EOK; } +void hr_raid0_status_event(hr_volume_t *vol) +{ + fibril_mutex_lock(&vol->lock); + (void) hr_raid0_update_vol_status(vol); + fibril_mutex_unlock(&vol->lock); +} + static errno_t hr_raid0_bd_open(bd_srvs_t *bds, bd_srv_t *bd) { HR_DEBUG("hr_bd_open()\n"); diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index cd12120dca..057b378d00 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -124,6 +124,13 @@ errno_t hr_raid1_init(hr_volume_t *vol) return EOK; } +void hr_raid1_status_event(hr_volume_t *vol) +{ + fibril_mutex_lock(&vol->lock); + (void) hr_raid1_update_vol_status(vol); + fibril_mutex_unlock(&vol->lock); +} + static errno_t hr_raid1_bd_open(bd_srvs_t *bds, bd_srv_t *bd) { HR_DEBUG("hr_bd_open()\n"); diff --git a/uspace/srv/bd/hr/raid4.c b/uspace/srv/bd/hr/raid4.c index 2d6b45d791..29739e8523 100644 --- a/uspace/srv/bd/hr/raid4.c +++ b/uspace/srv/bd/hr/raid4.c @@ -137,6 +137,13 @@ errno_t hr_raid4_init(hr_volume_t *vol) return EOK; } +void hr_raid4_status_event(hr_volume_t *vol) +{ + fibril_mutex_lock(&vol->lock); + (void) hr_raid4_update_vol_status(vol); + fibril_mutex_unlock(&vol->lock); +} + static errno_t hr_raid4_bd_open(bd_srvs_t *bds, bd_srv_t *bd) { HR_DEBUG("hr_bd_open()\n"); diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 62e2d49207..4ef0c3b693 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -134,6 +134,13 @@ errno_t hr_raid5_init(hr_volume_t *vol) return EOK; } +void hr_raid5_status_event(hr_volume_t *vol) +{ + fibril_mutex_lock(&vol->lock); + (void) hr_raid5_update_vol_status(vol); + fibril_mutex_unlock(&vol->lock); +} + static errno_t hr_raid5_bd_open(bd_srvs_t *bds, bd_srv_t *bd) { HR_DEBUG("hr_bd_open()\n"); diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index c973619012..4bec775b74 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -49,6 +49,7 @@ typedef struct hr_volume hr_volume_t; typedef struct hr_ops { errno_t (*create)(hr_volume_t *); errno_t (*init)(hr_volume_t *); + void (*status_event)(hr_volume_t *); } hr_ops_t; typedef struct hr_volume { @@ -88,6 +89,11 @@ extern errno_t hr_raid1_init(hr_volume_t *); extern errno_t hr_raid4_init(hr_volume_t *); extern errno_t hr_raid5_init(hr_volume_t *); +extern void hr_raid0_status_event(hr_volume_t *); +extern void hr_raid1_status_event(hr_volume_t *); +extern void hr_raid4_status_event(hr_volume_t *); +extern void hr_raid5_status_event(hr_volume_t *); + #endif /** @} From e76e12d8e131cb57d50cec65555687c51bc2259f Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 22 Nov 2024 19:07:26 +0100 Subject: [PATCH 071/324] hr: add hr_count_extents(volume, state) Counts volume extents in some state. --- uspace/srv/bd/hr/util.c | 11 +++++++++++ uspace/srv/bd/hr/util.h | 1 + 2 files changed, 12 insertions(+) diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 465a178b9b..6ed7862dc3 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -236,5 +236,16 @@ void hr_sync_all_extents(hr_volume_t *vol) fibril_mutex_unlock(&vol->lock); } +size_t hr_count_extents(hr_volume_t *vol, hr_ext_status_t status) +{ + size_t count = 0; + for (size_t i = 0; i < vol->dev_no; i++) { + if (vol->extents[i].status == status) + count++; + } + + return count; +} + /** @} */ diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index 6ba9ab3807..502b82f87c 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -57,6 +57,7 @@ extern errno_t hr_check_ba_range(hr_volume_t *, size_t, uint64_t); extern void hr_add_ba_offset(hr_volume_t *, uint64_t *); extern void hr_update_ext_status(hr_volume_t *, uint64_t, hr_ext_status_t); extern void hr_sync_all_extents(hr_volume_t *); +extern size_t hr_count_extents(hr_volume_t *, hr_ext_status_t); #endif From 06f27627ff2df05506f9dd30373602f0d7d129db Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 22 Nov 2024 19:36:16 +0100 Subject: [PATCH 072/324] hr: add option to write metadata to one extent --- uspace/srv/bd/hr/superblock.c | 100 ++++++++++++++++++++++++++-------- uspace/srv/bd/hr/superblock.h | 1 + 2 files changed, 78 insertions(+), 23 deletions(-) diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index 599bfc2b10..dfb69e065c 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -50,6 +50,7 @@ #include "var.h" static errno_t read_metadata(service_id_t, hr_metadata_t *); +static errno_t hr_fill_meta_from_vol(hr_volume_t *, hr_metadata_t *); errno_t hr_write_meta_to_vol(hr_volume_t *vol) { @@ -57,7 +58,6 @@ errno_t hr_write_meta_to_vol(hr_volume_t *vol) errno_t rc; size_t i; - size_t meta_blkno; /* blocks needed to write metadata */ hr_metadata_t *metadata; uuid_t uuid; @@ -65,28 +65,10 @@ errno_t hr_write_meta_to_vol(hr_volume_t *vol) if (metadata == NULL) return ENOMEM; - meta_blkno = (HR_META_OFF + HR_META_SIZE); - if (vol->level != HR_LVL_1) - meta_blkno *= vol->dev_no; - - if (vol->nblocks < meta_blkno) { - HR_ERROR("not enough blocks to write metadat\n"); - rc = EINVAL; - goto error; - } else if (vol->nblocks == meta_blkno) { - HR_ERROR("there would be zero data blocks after writing " - "metadata, aborting"); - rc = EINVAL; + rc = hr_fill_meta_from_vol(vol, metadata); + if (rc != EOK) goto error; - } - metadata->magic = host2uint64_t_le(HR_MAGIC); - metadata->extent_no = host2uint32_t_le(vol->dev_no); - metadata->level = host2uint32_t_le(vol->level); - metadata->nblocks = host2uint64_t_le(vol->nblocks); - metadata->data_blkno = host2uint64_t_le(vol->data_blkno); - metadata->data_offset = host2uint32_t_le(vol->data_offset); - metadata->strip_size = host2uint32_t_le(vol->strip_size); for (i = 0; i < vol->dev_no; i++) { metadata->index = host2uint32_t_le(i); @@ -95,8 +77,6 @@ errno_t hr_write_meta_to_vol(hr_volume_t *vol) goto error; uuid_encode(&uuid, metadata->uuid); - str_cpy(metadata->devname, HR_DEVNAME_LEN, vol->devname); - rc = block_write_direct(vol->extents[i].svc_id, HR_META_OFF, HR_META_SIZE, metadata); if (rc != EOK) @@ -110,6 +90,80 @@ errno_t hr_write_meta_to_vol(hr_volume_t *vol) return rc; } +errno_t hr_write_meta_to_ext(hr_volume_t *vol, size_t ext) +{ + HR_DEBUG("hr_write_meta_to_vol()\n"); + + errno_t rc; + hr_metadata_t *metadata; + uuid_t uuid; + + metadata = calloc(1, HR_META_SIZE * vol->bsize); + if (metadata == NULL) + return ENOMEM; + + rc = hr_fill_meta_from_vol(vol, metadata); + if (rc != EOK) + goto error; + + metadata->index = host2uint32_t_le(ext); + + rc = uuid_generate(&uuid); + if (rc != EOK) + goto error; + uuid_encode(&uuid, metadata->uuid); + + rc = block_write_direct(vol->extents[ext].svc_id, HR_META_OFF, + HR_META_SIZE, metadata); + if (rc != EOK) + goto error; + +error: + free(metadata); + return rc; +} + +/* + * Fill metadata members from + * specified volume. + * + * Does not fill extent index and UUID. + */ +static errno_t hr_fill_meta_from_vol(hr_volume_t *vol, hr_metadata_t *metadata) +{ + HR_DEBUG("hr_fill_meta_from_vol()\n"); + + size_t meta_blkno; /* blocks needed to write metadata */ + + meta_blkno = (HR_META_OFF + HR_META_SIZE); + if (vol->level != HR_LVL_1) + meta_blkno *= vol->dev_no; + + if (vol->nblocks < meta_blkno) { + HR_ERROR("hr_fill_meta_from_vol(): volume \"%s\" does not " + " have enough space to store metada, aborting\n", + vol->devname); + return EINVAL; + } else if (vol->nblocks == meta_blkno) { + HR_ERROR("hr_fill_meta_from_vol(): volume \"%s\" would have " + "zero data blocks after writing metadata, aborting\n", + vol->devname); + return EINVAL; + } + + metadata->magic = host2uint64_t_le(HR_MAGIC); + metadata->extent_no = host2uint32_t_le(vol->dev_no); + metadata->level = host2uint32_t_le(vol->level); + metadata->nblocks = host2uint64_t_le(vol->nblocks); + metadata->data_blkno = host2uint64_t_le(vol->data_blkno); + metadata->data_offset = host2uint32_t_le(vol->data_offset); + metadata->strip_size = host2uint32_t_le(vol->strip_size); + + str_cpy(metadata->devname, HR_DEVNAME_LEN, vol->devname); + + return EOK; +} + static errno_t validate_meta(hr_metadata_t *md) { if (uint64_t_le2host(md->magic) != HR_MAGIC) { diff --git a/uspace/srv/bd/hr/superblock.h b/uspace/srv/bd/hr/superblock.h index c6e74f852c..73504f43de 100644 --- a/uspace/srv/bd/hr/superblock.h +++ b/uspace/srv/bd/hr/superblock.h @@ -60,6 +60,7 @@ typedef struct hr_metadata { } hr_metadata_t; extern errno_t hr_write_meta_to_vol(hr_volume_t *); +extern errno_t hr_write_meta_to_ext(hr_volume_t *, size_t); extern errno_t hr_fill_vol_from_meta(hr_volume_t *); #endif From 5b320ac8b95b9187c0be19f4f192b32cdac432f3 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 22 Nov 2024 19:38:49 +0100 Subject: [PATCH 073/324] hr: hotspares + RAID1 rebuild --- uspace/app/hrctl/hrctl.c | 37 +++++- uspace/lib/device/include/hr.h | 11 +- uspace/lib/device/include/ipc/hr.h | 1 + uspace/lib/device/src/hr.c | 47 +++++++ uspace/srv/bd/hr/hr.c | 37 ++++++ uspace/srv/bd/hr/raid1.c | 189 +++++++++++++++++++++++++++-- uspace/srv/bd/hr/var.h | 18 ++- 7 files changed, 326 insertions(+), 14 deletions(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index cdd6ff61bc..c07d274e2d 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -68,6 +68,7 @@ static const char usage_str[] = " -1 mirroring\n" " -4 parity on one extent\n" " -5 distributed parity\n" + " -H, --hotspare=DEV add hotspare extent\n" "\n" "When specifying name for creation or assembly, the device name\n" "is automatically prepended with \"devices/\" prefix.\n" @@ -79,6 +80,8 @@ static const char usage_str[] = " hrctl --assemble hr0 -n 2 devices/\\hw\\0 devices/\\hw\\1\n" " - assembles RAID device named /hr0 consisting of 2 drives,\n" " that were previously in an array\n" + " hrctl devices/hr0 --hotspare=devices/disk10\n" + " - adds \"devices/disk10\" as hotspare extent\n" "Limitations:\n" " - device name must be less than 32 characters in size\n"; @@ -92,6 +95,7 @@ static struct option const long_options[] = { { "assemble-file", required_argument, 0, 'A' }, { "destroy", required_argument, 0, 'D' }, { "fail-extent", required_argument, 0, 'F' }, + { "hotspare", required_argument, 0, 'H' }, { 0, 0, 0, 0 } }; @@ -246,7 +250,7 @@ int main(int argc, char **argv) optind = 0; while (c != -1) { - c = getopt_long(argc, argv, "hsC:c:A:a:l:0145Ln:D:F:", + c = getopt_long(argc, argv, "hsC:c:A:a:l:0145Ln:D:F:H:", long_options, NULL); switch (c) { case 'h': @@ -344,6 +348,37 @@ int main(int argc, char **argv) return 1; } break; + case 'H': + if (optind != 3 && argc != 4) + goto bad; + + service_id_t hotspare; + service_id_t vol_svc_id; + + rc = loc_service_get_id(argv[1], &vol_svc_id, 0); + if (rc != EOK) { + printf("hrctl: error resolving volume \"%s\", " + "aborting extent addition\n", argv[1]); + goto bad; + } + + rc = loc_service_get_id(optarg, &hotspare, 0); + if (rc != EOK) { + printf("hrctl: error resolving device \"%s\", " + "aborting extent addition\n", optarg); + goto bad; + } + + rc = hr_add_hotspare(vol_svc_id, hotspare); + if (rc != EOK) + printf("hrctl: hr_add_hotspare() rc: %s\n", + str_error(rc)); + + free(cfg); + if (rc != EOK) + return 1; + else + return 0; } } diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index eaa0b49957..8443bbf78c 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -42,6 +42,7 @@ /* for now */ #define HR_MAX_EXTENTS 4 +#define HR_MAX_HOTSPARES HR_MAX_EXTENTS #define HR_DEVNAME_LEN 32 @@ -56,13 +57,16 @@ typedef enum hr_level { typedef enum hr_vol_status { HR_VOL_ONLINE, /* OK, OPTIMAL */ HR_VOL_FAULTY, - HR_VOL_DEGRADED /* also used for partial, but usable mirror */ + HR_VOL_DEGRADED, /* also used for partial, but usable mirror */ + HR_VOL_REBUILD } hr_vol_status_t; typedef enum hr_ext_status { HR_EXT_ONLINE, /* OK */ HR_EXT_MISSING, - HR_EXT_FAILED + HR_EXT_FAILED, + HR_EXT_REBUILD, + HR_EXT_HOTSPARE } hr_ext_status_t; typedef struct hr { @@ -83,7 +87,9 @@ typedef struct hr_extent { typedef struct hr_vol_info { hr_extent_t extents[HR_MAX_EXTENTS]; + hr_extent_t hotspares[HR_MAX_HOTSPARES]; size_t extent_no; + size_t hotspare_no; service_id_t svc_id; hr_level_t level; uint64_t nblocks; @@ -97,6 +103,7 @@ extern void hr_sess_destroy(hr_t *); extern errno_t hr_create(hr_t *, hr_config_t *, bool); extern errno_t hr_stop(const char *, long); +extern errno_t hr_add_hotspare(service_id_t, service_id_t); extern errno_t hr_print_status(void); extern const char *hr_get_vol_status_msg(hr_vol_status_t); diff --git a/uspace/lib/device/include/ipc/hr.h b/uspace/lib/device/include/ipc/hr.h index 694b461600..2fb60fb6d3 100644 --- a/uspace/lib/device/include/ipc/hr.h +++ b/uspace/lib/device/include/ipc/hr.h @@ -41,6 +41,7 @@ typedef enum { HR_CREATE = IPC_FIRST_USER_METHOD, HR_ASSEMBLE, HR_STOP, + HR_ADD_HOTSPARE, HR_STATUS } hr_request_t; diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index abc6c799b3..b19bbcdd20 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -165,6 +165,24 @@ static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info) else printf(" %s %zu %s\n", hr_get_ext_status_msg(ext->status), i, devname); } + + if (vol_info->hotspare_no == 0) + return EOK; + + printf("hotspares: [status] [index] [devname]\n"); + for (i = 0; i < vol_info->hotspare_no; i++) { + ext = &vol_info->hotspares[i]; + if (ext->status == HR_EXT_MISSING) { + devname = (char *) "MISSING-devname"; + } else { + rc = loc_service_get_name(ext->svc_id, &devname); + if (rc != EOK) + return rc; + } + printf(" %s %zu %s\n", + hr_get_ext_status_msg(ext->status), i, devname); + } + return EOK; } @@ -198,6 +216,29 @@ errno_t hr_stop(const char *devname, long extent) return rc; } +errno_t hr_add_hotspare(service_id_t vol_svc_id, service_id_t hs_svc_id) +{ + hr_t *hr; + errno_t rc; + async_exch_t *exch; + + rc = hr_sess_init(&hr); + if (rc != EOK) + return rc; + + exch = async_exchange_begin(hr->sess); + if (exch == NULL) { + rc = EINVAL; + goto error; + } + + rc = async_req_2_0(exch, HR_ADD_HOTSPARE, vol_svc_id, hs_svc_id); + async_exchange_end(exch); +error: + hr_sess_destroy(hr); + return rc; +} + errno_t hr_print_status(void) { hr_t *hr; @@ -276,6 +317,8 @@ const char *hr_get_vol_status_msg(hr_vol_status_t status) return "FAULTY"; case HR_VOL_DEGRADED: return "DEGRADED"; + case HR_VOL_REBUILD: + return "REBUILD"; default: return "UNKNOWN"; } @@ -290,6 +333,10 @@ const char *hr_get_ext_status_msg(hr_ext_status_t status) return "MISSING"; case HR_EXT_FAILED: return "FAILED"; + case HR_EXT_REBUILD: + return "REBUILD"; + case HR_EXT_HOTSPARE: + return "HOTSPARE"; default: return "UNKNOWN"; } diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index f295afb211..52653119af 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -190,6 +190,7 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) new_volume->hr_ops.create = hr_raid1_create; new_volume->hr_ops.init = hr_raid1_init; new_volume->hr_ops.status_event = hr_raid1_status_event; + new_volume->hr_ops.add_hotspare = hr_raid1_add_hotspare; break; case HR_LVL_0: new_volume->hr_ops.create = hr_raid0_create; @@ -286,6 +287,36 @@ static void hr_stop_srv(ipc_call_t *icall) async_answer_0(icall, rc); } +static void hr_add_hotspare_srv(ipc_call_t *icall) +{ + HR_DEBUG("hr_add_hotspare()\n"); + + errno_t rc = EOK; + service_id_t vol_svc_id; + service_id_t hotspare; + hr_volume_t *vol; + + vol_svc_id = ipc_get_arg1(icall); + hotspare = ipc_get_arg2(icall); + + vol = hr_get_volume(vol_svc_id); + if (vol == NULL) { + async_answer_0(icall, ENOENT); + return; + } + + if (vol->hr_ops.add_hotspare == NULL) { + HR_DEBUG("hr_add_hotspare(): not supported on RAID level %d\n", + vol->level); + async_answer_0(icall, ENOTSUP); + return; + } + + rc = vol->hr_ops.add_hotspare(vol, hotspare); + + async_answer_0(icall, rc); +} + static void hr_print_status_srv(ipc_call_t *icall) { HR_DEBUG("hr_status_srv()\n"); @@ -317,8 +348,11 @@ static void hr_print_status_srv(ipc_call_t *icall) list_foreach(hr_volumes, lvolumes, hr_volume_t, vol) { memcpy(info.extents, vol->extents, sizeof(hr_extent_t) * HR_MAX_EXTENTS); + memcpy(info.hotspares, vol->hotspares, + sizeof(hr_extent_t) * HR_MAX_HOTSPARES); info.svc_id = vol->svc_id; info.extent_no = vol->dev_no; + info.hotspare_no = vol->hotspare_no; info.level = vol->level; /* print usable number of blocks */ info.nblocks = vol->data_blkno; @@ -376,6 +410,9 @@ static void hr_ctl_conn(ipc_call_t *icall, void *arg) case HR_STOP: hr_stop_srv(&call); break; + case HR_ADD_HOTSPARE: + hr_add_hotspare_srv(&call); + break; case HR_STATUS: hr_print_status_srv(&call); break; diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 057b378d00..451f30b145 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -57,6 +57,7 @@ static errno_t hr_raid1_update_vol_status(hr_volume_t *); static void handle_extent_error(hr_volume_t *, size_t, errno_t); static errno_t hr_raid1_bd_op(hr_bd_op_type_t, bd_srv_t *, aoff64_t, size_t, void *, const void *, size_t); +static errno_t hr_raid1_rebuild(void *); /* bdops */ static errno_t hr_raid1_bd_open(bd_srvs_t *, bd_srv_t *); @@ -131,6 +132,41 @@ void hr_raid1_status_event(hr_volume_t *vol) fibril_mutex_unlock(&vol->lock); } +errno_t hr_raid1_add_hotspare(hr_volume_t *vol, service_id_t hotspare) +{ + HR_DEBUG("hr_raid1_add_hotspare()\n"); + + fibril_mutex_lock(&vol->lock); + + if (vol->hotspare_no >= HR_MAX_HOTSPARES) { + HR_ERROR("hr_raid1_add_hotspare(): cannot add more hotspares " + "to \"%s\"\n", vol->devname); + fibril_mutex_unlock(&vol->lock); + return ELIMIT; + } + + vol->hotspares[vol->hotspare_no].svc_id = hotspare; + vol->hotspares[vol->hotspare_no].status = HR_EXT_HOTSPARE; + vol->hotspare_no++; + + /* + * If the volume is degraded, start rebuild right away. + */ + if (vol->status == HR_VOL_DEGRADED) { + HR_DEBUG("hr_raid1_add_hotspare(): volume in DEGRADED state, " + "spawning new rebuild fibril\n"); + fid_t fib = fibril_create(hr_raid1_rebuild, vol); + if (fib == 0) + return EINVAL; + fibril_start(fib); + fibril_detach(fib); + } + + fibril_mutex_unlock(&vol->lock); + + return EOK; +} + static errno_t hr_raid1_bd_open(bd_srvs_t *bds, bd_srv_t *bd) { HR_DEBUG("hr_bd_open()\n"); @@ -179,7 +215,8 @@ static errno_t hr_raid1_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb) static errno_t hr_raid1_check_vol_status(hr_volume_t *vol) { if (vol->status == HR_VOL_ONLINE || - vol->status == HR_VOL_DEGRADED) + vol->status == HR_VOL_DEGRADED || + vol->status == HR_VOL_REBUILD) return EOK; return EINVAL; } @@ -191,10 +228,7 @@ static errno_t hr_raid1_check_vol_status(hr_volume_t *vol) static errno_t hr_raid1_update_vol_status(hr_volume_t *vol) { hr_vol_status_t old_state = vol->status; - size_t healthy = 0; - for (size_t i = 0; i < vol->dev_no; i++) - if (vol->extents[i].status == HR_EXT_ONLINE) - healthy++; + size_t healthy = hr_count_extents(vol, HR_EXT_ONLINE); if (healthy == 0) { if (old_state != HR_VOL_FAULTY) { @@ -205,11 +239,21 @@ static errno_t hr_raid1_update_vol_status(hr_volume_t *vol) } return EINVAL; } else if (healthy < vol->dev_no) { - if (old_state != HR_VOL_DEGRADED) { + if (old_state != HR_VOL_DEGRADED && + old_state != HR_VOL_REBUILD) { HR_WARN("RAID 1 array \"%s\" (%lu) has some " - "inactive extent(s), marking volume as DEGRADED", + "unusable extent(s), marking volume as DEGRADED", vol->devname, vol->svc_id); vol->status = HR_VOL_DEGRADED; + if (vol->hotspare_no > 0) { + fid_t fib = fibril_create(hr_raid1_rebuild, + vol); + if (fib == 0) { + return EINVAL; + } + fibril_start(fib); + fibril_detach(fib); + } } return EOK; } else { @@ -308,5 +352,136 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, return rc; } +/* + * Put the last HOTSPARE extent in place + * of first DEGRADED, and start the rebuild. + */ +static errno_t hr_raid1_rebuild(void *arg) +{ + HR_DEBUG("hr_raid1_rebuild()\n"); + + hr_volume_t *vol = arg; + void *buf = NULL; + errno_t rc = EOK; + + fibril_mutex_lock(&vol->lock); + + if (vol->hotspare_no == 0) { + HR_WARN("hr_raid1_rebuild(): no free hotspares on \"%s\", " + "aborting rebuild\n", vol->devname); + /* retval isn't checked for now */ + goto end; + } + + size_t bad = vol->dev_no; + for (size_t i = 0; i < vol->dev_no; i++) { + if (vol->extents[i].status == HR_EXT_FAILED) { + bad = i; + break; + } + } + + if (bad == vol->dev_no) { + HR_WARN("hr_raid1_rebuild(): no bad extent on \"%s\", " + "aborting rebuild\n", vol->devname); + /* retval isn't checked for now */ + goto end; + } + + block_fini(vol->extents[bad].svc_id); + + size_t hotspare_idx = vol->hotspare_no - 1; + + vol->extents[bad].svc_id = vol->hotspares[hotspare_idx].svc_id; + hr_update_ext_status(vol, bad, HR_EXT_REBUILD); + + vol->hotspares[hotspare_idx].svc_id = 0; + vol->hotspares[hotspare_idx].status = HR_EXT_MISSING; + vol->hotspare_no--; + + HR_WARN("hr_raid1_rebuild(): changing volume \"%s\" (%lu) state " + "from %s to %s\n", vol->devname, vol->svc_id, + hr_get_vol_status_msg(vol->status), + hr_get_vol_status_msg(HR_VOL_REBUILD)); + vol->status = HR_VOL_REBUILD; + + hr_extent_t *hotspare = &vol->extents[bad]; + + HR_DEBUG("hr_raid1_rebuild(): initing (%lu)\n", hotspare->svc_id); + + rc = block_init(hotspare->svc_id); + if (rc != EOK) { + HR_ERROR("hr_raid1_rebuild(): initing (%lu) failed, " + "aborting rebuild\n", hotspare->svc_id); + goto end; + } + + size_t left = vol->data_blkno; + size_t max_blks = DATA_XFER_LIMIT / vol->bsize; + buf = malloc(max_blks * vol->bsize); + + hr_extent_t *ext; + size_t rebuild_ext_idx = bad; + + size_t cnt; + uint64_t ba = 0; + hr_add_ba_offset(vol, &ba); + while (left != 0) { + cnt = min(max_blks, left); + for (size_t i = 0; i < vol->dev_no; i++) { + ext = &vol->extents[i]; + if (ext->status == HR_EXT_ONLINE) { + rc = block_read_direct(ext->svc_id, ba, cnt, + buf); + if (rc != EOK) { + handle_extent_error(vol, i, rc); + if (i + 1 < vol->dev_no) { + /* still might have one ONLINE */ + continue; + } else { + HR_ERROR("rebuild on \"%s\" (%lu), failed due to " + "too many failed extents\n", + vol->devname, vol->svc_id); + goto end; + } + } + break; + } + } + + rc = block_write_direct(hotspare->svc_id, ba, cnt, buf); + if (rc != EOK) { + handle_extent_error(vol, rebuild_ext_idx, rc); + HR_ERROR("rebuild on \"%s\" (%lu), extent number %lu\n", + vol->devname, vol->svc_id, rebuild_ext_idx); + goto end; + + } + + ba += cnt; + left -= cnt; + } + + HR_DEBUG("hr_raid1_rebuild(): rebuild finished on \"%s\" (%lu), " + "extent number %lu\n", vol->devname, vol->svc_id, hotspare_idx); + + hr_update_ext_status(vol, hotspare_idx, HR_EXT_ONLINE); + /* + * For now write metadata at the end, because + * we don't sync metada accross extents yet. + */ + hr_write_meta_to_ext(vol, bad); +end: + (void) hr_raid1_update_vol_status(vol); + + fibril_mutex_unlock(&vol->lock); + + if (buf != NULL) + free(buf); + + /* retval isn't checked anywhere for now */ + return rc; +} + /** @} */ diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index 4bec775b74..bce088bc36 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -50,24 +50,32 @@ typedef struct hr_ops { errno_t (*create)(hr_volume_t *); errno_t (*init)(hr_volume_t *); void (*status_event)(hr_volume_t *); + errno_t (*add_hotspare)(hr_volume_t *, service_id_t); } hr_ops_t; typedef struct hr_volume { hr_ops_t hr_ops; bd_srvs_t hr_bds; + link_t lvolumes; fibril_mutex_t lock; - char devname[HR_DEVNAME_LEN]; + + size_t dev_no; hr_extent_t extents[HR_MAX_EXTENTS]; + + size_t hotspare_no; + hr_extent_t hotspares[HR_MAX_EXTENTS]; + + size_t bsize; uint64_t nblocks; uint64_t data_blkno; uint32_t data_offset; /* in blocks */ uint32_t strip_size; + service_id_t svc_id; - size_t bsize; - size_t dev_no; - hr_level_t level; hr_vol_status_t status; + hr_level_t level; + char devname[HR_DEVNAME_LEN]; } hr_volume_t; typedef enum { @@ -94,6 +102,8 @@ extern void hr_raid1_status_event(hr_volume_t *); extern void hr_raid4_status_event(hr_volume_t *); extern void hr_raid5_status_event(hr_volume_t *); +extern errno_t hr_raid1_add_hotspare(hr_volume_t *, service_id_t); + #endif /** @} From d0f074457b5f4784be5e962dba29681ee959bf5c Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 22 Nov 2024 19:44:12 +0100 Subject: [PATCH 074/324] hr: RAID1: break after first successful read --- uspace/srv/bd/hr/raid1.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 451f30b145..5d8bf66590 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -320,10 +320,12 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, continue; rc = block_read_direct(vol->extents[i].svc_id, ba, cnt, data_read); - if (rc != EOK) + if (rc != EOK) { handle_extent_error(vol, i, rc); - else + } else { successful++; + break; + } } break; case HR_BD_WRITE: From b8409b9c4af46ca08e0a3c04c51cfa85776b5671 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 22 Nov 2024 20:01:05 +0100 Subject: [PATCH 075/324] hr: RAID1: fix WRITE to rebuilt extent When writing to extent that is being rebuilt, allow writes only to (ba < current rebuild position). --- uspace/srv/bd/hr/raid1.c | 13 ++++++++++++- uspace/srv/bd/hr/var.h | 2 ++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 5d8bf66590..185cca3122 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -330,7 +330,16 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, break; case HR_BD_WRITE: for (i = 0; i < vol->dev_no; i++) { - if (vol->extents[i].status != HR_EXT_ONLINE) + if (vol->extents[i].status != HR_EXT_ONLINE || + (vol->extents[i].status == HR_EXT_REBUILD && + ba >= vol->rebuild_blk)) + /* + * When the extent is being rebuilt, + * we only write to the part that is already + * rebuilt. If ba is more than vol->rebuild_blk, + * the write is going to be replicated later + * in the rebuild. TODO: test + */ continue; rc = block_write_direct(vol->extents[i].svc_id, ba, cnt, data_write); @@ -394,6 +403,7 @@ static errno_t hr_raid1_rebuild(void *arg) size_t hotspare_idx = vol->hotspare_no - 1; + vol->rebuild_blk = 0; vol->extents[bad].svc_id = vol->hotspares[hotspare_idx].svc_id; hr_update_ext_status(vol, bad, HR_EXT_REBUILD); @@ -429,6 +439,7 @@ static errno_t hr_raid1_rebuild(void *arg) uint64_t ba = 0; hr_add_ba_offset(vol, &ba); while (left != 0) { + vol->rebuild_blk = ba; cnt = min(max_blks, left); for (size_t i = 0; i < vol->dev_no; i++) { ext = &vol->extents[i]; diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index bce088bc36..350efa97b0 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -72,6 +72,8 @@ typedef struct hr_volume { uint32_t data_offset; /* in blocks */ uint32_t strip_size; + uint64_t rebuild_blk; + service_id_t svc_id; hr_vol_status_t status; hr_level_t level; From b56d88ffc9c5fa76529bc7488f393df4670da884 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 22 Nov 2024 22:10:35 +0100 Subject: [PATCH 076/324] bdwrite: fix writing --- uspace/app/bdwrite/bdwrite.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/uspace/app/bdwrite/bdwrite.c b/uspace/app/bdwrite/bdwrite.c index 7c1821e378..5294e94dbe 100644 --- a/uspace/app/bdwrite/bdwrite.c +++ b/uspace/app/bdwrite/bdwrite.c @@ -107,19 +107,19 @@ int main(int argc, char **argv) } uint64_t to_alloc = min(DATA_XFER_LIMIT, bsize * blkcnt); - uint8_t *buf = calloc(to_alloc / bsize, bsize); + uint8_t *buf = malloc(to_alloc); if (buf == NULL) { rc = ENOMEM; goto end; } uint64_t left = blkcnt; - while (left > 0) { + while (left != 0) { uint64_t blks_to_write = min(to_alloc / bsize, left); uint8_t *ptr = buf; for (size_t i = 0; i < blks_to_write; i++) { /* memset(ptr, (i + 1) % 0x100, bsize); */ memset(ptr, 'A' + (i % 26), bsize); - ptr = (uint8_t *)((uintptr_t) ptr + bsize); + ptr += bsize; } rc = block_write_direct(dev, off, blks_to_write, buf); if (rc != EOK) { @@ -127,6 +127,7 @@ int main(int argc, char **argv) goto end; } left -= blks_to_write; + off += blks_to_write; } end: free(buf); From f81960c5dd5ffc19dec3d22be6176802972b2639 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 22 Nov 2024 22:23:38 +0100 Subject: [PATCH 077/324] hr: RAID1: style --- uspace/srv/bd/hr/raid1.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 185cca3122..4c359fa5a8 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -54,7 +54,7 @@ extern loc_srv_t *hr_srv; static errno_t hr_raid1_check_vol_status(hr_volume_t *); static errno_t hr_raid1_update_vol_status(hr_volume_t *); -static void handle_extent_error(hr_volume_t *, size_t, errno_t); +static void hr_raid1_handle_extent_error(hr_volume_t *, size_t, errno_t); static errno_t hr_raid1_bd_op(hr_bd_op_type_t, bd_srv_t *, aoff64_t, size_t, void *, const void *, size_t); static errno_t hr_raid1_rebuild(void *); @@ -267,7 +267,7 @@ static errno_t hr_raid1_update_vol_status(hr_volume_t *vol) } } -static void handle_extent_error(hr_volume_t *vol, size_t extent, +static void hr_raid1_handle_extent_error(hr_volume_t *vol, size_t extent, errno_t rc) { if (rc == ENOENT) @@ -309,7 +309,7 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, continue; rc = block_sync_cache(vol->extents[i].svc_id, ba, cnt); if (rc != EOK && rc != ENOTSUP) - handle_extent_error(vol, i, rc); + hr_raid1_handle_extent_error(vol, i, rc); else successful++; } @@ -321,7 +321,7 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, rc = block_read_direct(vol->extents[i].svc_id, ba, cnt, data_read); if (rc != EOK) { - handle_extent_error(vol, i, rc); + hr_raid1_handle_extent_error(vol, i, rc); } else { successful++; break; @@ -344,7 +344,7 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, rc = block_write_direct(vol->extents[i].svc_id, ba, cnt, data_write); if (rc != EOK) - handle_extent_error(vol, i, rc); + hr_raid1_handle_extent_error(vol, i, rc); else successful++; } @@ -433,7 +433,6 @@ static errno_t hr_raid1_rebuild(void *arg) buf = malloc(max_blks * vol->bsize); hr_extent_t *ext; - size_t rebuild_ext_idx = bad; size_t cnt; uint64_t ba = 0; @@ -447,7 +446,7 @@ static errno_t hr_raid1_rebuild(void *arg) rc = block_read_direct(ext->svc_id, ba, cnt, buf); if (rc != EOK) { - handle_extent_error(vol, i, rc); + hr_raid1_handle_extent_error(vol, i, rc); if (i + 1 < vol->dev_no) { /* still might have one ONLINE */ continue; @@ -464,9 +463,10 @@ static errno_t hr_raid1_rebuild(void *arg) rc = block_write_direct(hotspare->svc_id, ba, cnt, buf); if (rc != EOK) { - handle_extent_error(vol, rebuild_ext_idx, rc); - HR_ERROR("rebuild on \"%s\" (%lu), extent number %lu\n", - vol->devname, vol->svc_id, rebuild_ext_idx); + hr_raid1_handle_extent_error(vol, bad, rc); + HR_ERROR("rebuild on \"%s\" (%lu), failed due to " + "the rebuilt extent number %lu failing\n", + vol->devname, vol->svc_id, bad); goto end; } @@ -478,7 +478,7 @@ static errno_t hr_raid1_rebuild(void *arg) HR_DEBUG("hr_raid1_rebuild(): rebuild finished on \"%s\" (%lu), " "extent number %lu\n", vol->devname, vol->svc_id, hotspare_idx); - hr_update_ext_status(vol, hotspare_idx, HR_EXT_ONLINE); + hr_update_ext_status(vol, bad, HR_EXT_ONLINE); /* * For now write metadata at the end, because * we don't sync metada accross extents yet. From 30140c1ba6529eb7eea93638ce863d07b5612dd5 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 22 Nov 2024 22:27:35 +0100 Subject: [PATCH 078/324] hr: RAID4: hotspare + rebuild --- uspace/srv/bd/hr/hr.c | 1 + uspace/srv/bd/hr/raid4.c | 198 +++++++++++++++++++++++++++++++++++++-- uspace/srv/bd/hr/var.h | 1 + 3 files changed, 194 insertions(+), 6 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 52653119af..b9992bd573 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -201,6 +201,7 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) new_volume->hr_ops.create = hr_raid4_create; new_volume->hr_ops.init = hr_raid4_init; new_volume->hr_ops.status_event = hr_raid4_status_event; + new_volume->hr_ops.add_hotspare = hr_raid4_add_hotspare; break; case HR_LVL_5: new_volume->hr_ops.create = hr_raid5_create; diff --git a/uspace/srv/bd/hr/raid4.c b/uspace/srv/bd/hr/raid4.c index 29739e8523..77095e1258 100644 --- a/uspace/srv/bd/hr/raid4.c +++ b/uspace/srv/bd/hr/raid4.c @@ -57,6 +57,7 @@ extern loc_srv_t *hr_srv; static errno_t hr_raid4_vol_usable(hr_volume_t *); static ssize_t hr_raid4_get_bad_ext(hr_volume_t *); static errno_t hr_raid4_update_vol_status(hr_volume_t *); +static void hr_raid4_handle_extent_error(hr_volume_t *, size_t, errno_t); static void xor(void *, const void *, size_t); static errno_t hr_raid4_read_degraded(hr_volume_t *, uint64_t, uint64_t, void *, size_t); @@ -66,6 +67,7 @@ static errno_t hr_raid4_write_parity(hr_volume_t *, uint64_t, uint64_t, const void *, size_t); static errno_t hr_raid4_bd_op(hr_bd_op_type_t, bd_srv_t *, aoff64_t, size_t, void *, const void *, size_t); +static errno_t hr_raid4_rebuild(void *); /* bdops */ static errno_t hr_raid4_bd_open(bd_srvs_t *, bd_srv_t *); @@ -144,6 +146,41 @@ void hr_raid4_status_event(hr_volume_t *vol) fibril_mutex_unlock(&vol->lock); } +errno_t hr_raid4_add_hotspare(hr_volume_t *vol, service_id_t hotspare) +{ + HR_DEBUG("hr_raid4_add_hotspare()\n"); + + fibril_mutex_lock(&vol->lock); + + if (vol->hotspare_no >= HR_MAX_HOTSPARES) { + HR_ERROR("hr_raid4_add_hotspare(): cannot add more hotspares " + "to \"%s\"\n", vol->devname); + fibril_mutex_unlock(&vol->lock); + return ELIMIT; + } + + vol->hotspares[vol->hotspare_no].svc_id = hotspare; + vol->hotspares[vol->hotspare_no].status = HR_EXT_HOTSPARE; + vol->hotspare_no++; + + /* + * If the volume is degraded, start rebuild right away. + */ + if (vol->status == HR_VOL_DEGRADED) { + HR_DEBUG("hr_raid4_add_hotspare(): volume in DEGRADED state, " + "spawning new rebuild fibril\n"); + fid_t fib = fibril_create(hr_raid4_rebuild, vol); + if (fib == 0) + return EINVAL; + fibril_start(fib); + fibril_detach(fib); + } + + fibril_mutex_unlock(&vol->lock); + + return EOK; +} + static errno_t hr_raid4_bd_open(bd_srvs_t *bds, bd_srv_t *bd) { HR_DEBUG("hr_bd_open()\n"); @@ -227,17 +264,27 @@ static errno_t hr_raid4_update_vol_status(hr_volume_t *vol) } return EOK; case 1: - if (old_state != HR_VOL_DEGRADED) { + if (old_state != HR_VOL_DEGRADED && + old_state != HR_VOL_REBUILD) { HR_WARN("RAID 4 array \"%s\" (%lu) has 1 extent " "inactive, marking as DEGRADED", vol->devname, vol->svc_id); vol->status = HR_VOL_DEGRADED; + if (vol->hotspare_no > 0) { + fid_t fib = fibril_create(hr_raid4_rebuild, + vol); + if (fib == 0) { + return EINVAL; + } + fibril_start(fib); + fibril_detach(fib); + } } return EOK; default: if (old_state != HR_VOL_FAULTY) { HR_WARN("RAID 4 array \"%s\" (%lu) has more " - "than one 1 extent inactive, marking as FAULTY", + "than one 1 extent unusable, marking as FAULTY", vol->devname, vol->svc_id); vol->status = HR_VOL_FAULTY; } @@ -245,6 +292,15 @@ static errno_t hr_raid4_update_vol_status(hr_volume_t *vol) } } +static void hr_raid4_handle_extent_error(hr_volume_t *vol, size_t extent, + errno_t rc) +{ + if (rc == ENOENT) + hr_update_ext_status(vol, extent, HR_EXT_MISSING); + else if (rc != EOK) + hr_update_ext_status(vol, extent, HR_EXT_FAILED); +} + static void xor(void *dst, const void *src, size_t size) { size_t i; @@ -511,10 +567,7 @@ static errno_t hr_raid4_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, if (rc == ENOMEM) goto error; - if (rc == ENOENT) - hr_update_ext_status(vol, extent, HR_EXT_MISSING); - else if (rc != EOK) - hr_update_ext_status(vol, extent, HR_EXT_FAILED); + hr_raid4_handle_extent_error(vol, extent, rc); if (rc != EOK) { rc = hr_raid4_update_vol_status(vol); @@ -551,5 +604,138 @@ static errno_t hr_raid4_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, return rc; } +static errno_t hr_raid4_rebuild(void *arg) +{ + HR_DEBUG("hr_raid4_rebuild()\n"); + + hr_volume_t *vol = arg; + errno_t rc = EOK; + void *buf = NULL, *xorbuf = NULL; + + fibril_mutex_lock(&vol->lock); + + if (vol->hotspare_no == 0) { + HR_WARN("hr_raid4_rebuild(): no free hotspares on \"%s\", " + "aborting rebuild\n", vol->devname); + /* retval isn't checked for now */ + goto end; + } + + size_t bad = vol->dev_no; + for (size_t i = 0; i < vol->dev_no; i++) { + if (vol->extents[i].status == HR_EXT_FAILED) { + bad = i; + break; + } + } + + if (bad == vol->dev_no) { + HR_WARN("hr_raid4_rebuild(): no bad extent on \"%s\", " + "aborting rebuild\n", vol->devname); + /* retval isn't checked for now */ + goto end; + } + + block_fini(vol->extents[bad].svc_id); + + size_t hotspare_idx = vol->hotspare_no - 1; + + vol->extents[bad].svc_id = vol->hotspares[hotspare_idx].svc_id; + hr_update_ext_status(vol, bad, HR_EXT_REBUILD); + + vol->hotspares[hotspare_idx].svc_id = 0; + vol->hotspares[hotspare_idx].status = HR_EXT_MISSING; + vol->hotspare_no--; + + HR_WARN("hr_raid4_rebuild(): changing volume \"%s\" (%lu) state " + "from %s to %s\n", vol->devname, vol->svc_id, + hr_get_vol_status_msg(vol->status), + hr_get_vol_status_msg(HR_VOL_REBUILD)); + vol->status = HR_VOL_REBUILD; + + hr_extent_t *hotspare = &vol->extents[bad]; + + HR_DEBUG("hr_raid4_rebuild(): initing (%lu)\n", hotspare->svc_id); + + rc = block_init(hotspare->svc_id); + if (rc != EOK) { + HR_ERROR("hr_raid4_rebuild(): initing (%lu) failed, " + "aborting rebuild\n", hotspare->svc_id); + goto end; + } + + uint64_t max_blks = DATA_XFER_LIMIT / vol->bsize; + uint64_t left = vol->data_blkno / (vol->dev_no - 1); + buf = malloc(max_blks * vol->bsize); + xorbuf = malloc(max_blks * vol->bsize); + + uint64_t ba = 0, cnt; + hr_add_ba_offset(vol, &ba); + while (left != 0) { + cnt = min(left, max_blks); + + /* + * Almost the same as read_degraded, + * but we don't want to allocate new + * xorbuf each blk rebuild batch. + */ + bool first = true; + for (size_t i = 0; i < vol->dev_no; i++) { + if (i == bad) + continue; + rc = block_read_direct(vol->extents[i].svc_id, ba, cnt, + buf); + if (rc != EOK) { + hr_raid4_handle_extent_error(vol, i, rc); + HR_ERROR("rebuild on \"%s\" (%lu), failed due " + "to a failed ONLINE extent, number %lu\n", + vol->devname, vol->svc_id, i); + goto end; + } + + if (first) + memcpy(xorbuf, buf, cnt * vol->bsize); + else + xor(xorbuf, buf, cnt * vol->bsize); + + first = false; + } + + rc = block_write_direct(hotspare->svc_id, ba, cnt, xorbuf); + if (rc != EOK) { + hr_raid4_handle_extent_error(vol, bad, rc); + HR_ERROR("rebuild on \"%s\" (%lu), failed due to " + "the rebuilt extent number %lu failing\n", + vol->devname, vol->svc_id, bad); + goto end; + } + + ba += cnt; + left -= cnt; + } + + HR_DEBUG("hr_raid4_rebuild(): rebuild finished on \"%s\" (%lu), " + "extent number %lu\n", vol->devname, vol->svc_id, hotspare_idx); + + hr_update_ext_status(vol, bad, HR_EXT_ONLINE); + /* + * For now write metadata at the end, because + * we don't sync metada accross extents yet. + */ + hr_write_meta_to_ext(vol, bad); +end: + (void) hr_raid4_update_vol_status(vol); + + fibril_mutex_unlock(&vol->lock); + + if (buf != NULL) + free(buf); + + if (xorbuf != NULL) + free(xorbuf); + + return rc; +} + /** @} */ diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index 350efa97b0..c5502acb1b 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -105,6 +105,7 @@ extern void hr_raid4_status_event(hr_volume_t *); extern void hr_raid5_status_event(hr_volume_t *); extern errno_t hr_raid1_add_hotspare(hr_volume_t *, service_id_t); +extern errno_t hr_raid4_add_hotspare(hr_volume_t *, service_id_t); #endif From a56ac5d104d1ac76ca923673c261f7b6d96a9cea Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 22 Nov 2024 23:15:05 +0100 Subject: [PATCH 079/324] hr: fix RAID 4,5 parity xorring length --- uspace/srv/bd/hr/raid4.c | 2 +- uspace/srv/bd/hr/raid5.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/uspace/srv/bd/hr/raid4.c b/uspace/srv/bd/hr/raid4.c index 77095e1258..d8dc291805 100644 --- a/uspace/srv/bd/hr/raid4.c +++ b/uspace/srv/bd/hr/raid4.c @@ -469,7 +469,7 @@ static errno_t hr_raid4_write_parity(hr_volume_t *vol, uint64_t extent, memset(xorbuf, 0, len); for (i = 1; i < vol->dev_no; i++) { if (i == extent) { - xor(xorbuf, data, vol->bsize); + xor(xorbuf, data, len); } else { rc = block_read_direct(vol->extents[i].svc_id, block, cnt, buf); diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 4ef0c3b693..26ec53c717 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -409,13 +409,13 @@ static errno_t hr_raid5_write_parity(hr_volume_t *vol, uint64_t p_extent, if (i == p_extent) continue; if (i == extent) { - xor(xorbuf, data, vol->bsize); + xor(xorbuf, data, len); } else { rc = block_read_direct(vol->extents[i].svc_id, block, cnt, buf); if (rc != EOK) goto end; - xor(xorbuf, buf, vol->bsize); + xor(xorbuf, buf, len); } } From aa7864b3dfbb5bf9b30e2e59ae92dfa2698bcf59 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 22 Nov 2024 23:17:01 +0100 Subject: [PATCH 080/324] hr: RAID5: hotspare + rebuild --- uspace/srv/bd/hr/hr.c | 1 + uspace/srv/bd/hr/raid5.c | 196 ++++++++++++++++++++++++++++++++++++++- uspace/srv/bd/hr/var.h | 1 + 3 files changed, 193 insertions(+), 5 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index b9992bd573..26de98aa3a 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -207,6 +207,7 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) new_volume->hr_ops.create = hr_raid5_create; new_volume->hr_ops.init = hr_raid5_init; new_volume->hr_ops.status_event = hr_raid5_status_event; + new_volume->hr_ops.add_hotspare = hr_raid5_add_hotspare; break; default: HR_ERROR("unkown level: %d, aborting\n", new_volume->level); diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 26ec53c717..8faac5763a 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -57,6 +57,7 @@ extern loc_srv_t *hr_srv; static errno_t hr_raid5_vol_usable(hr_volume_t *); static ssize_t hr_raid5_get_bad_ext(hr_volume_t *); static errno_t hr_raid5_update_vol_status(hr_volume_t *); +static void hr_raid5_handle_extent_error(hr_volume_t *, size_t, errno_t); static void xor(void *, const void *, size_t); static errno_t hr_raid5_read_degraded(hr_volume_t *, uint64_t, uint64_t, void *, size_t); @@ -66,6 +67,7 @@ static errno_t hr_raid5_write_parity(hr_volume_t *, uint64_t, uint64_t, uint64_t, const void *, size_t); static errno_t hr_raid5_bd_op(hr_bd_op_type_t, bd_srv_t *, aoff64_t, size_t, void *, const void *, size_t); +static errno_t hr_raid5_rebuild(void *); /* bdops */ static errno_t hr_raid5_bd_open(bd_srvs_t *, bd_srv_t *); @@ -141,6 +143,41 @@ void hr_raid5_status_event(hr_volume_t *vol) fibril_mutex_unlock(&vol->lock); } +errno_t hr_raid5_add_hotspare(hr_volume_t *vol, service_id_t hotspare) +{ + HR_DEBUG("hr_raid5_add_hotspare()\n"); + + fibril_mutex_lock(&vol->lock); + + if (vol->hotspare_no >= HR_MAX_HOTSPARES) { + HR_ERROR("hr_raid5_add_hotspare(): cannot add more hotspares " + "to \"%s\"\n", vol->devname); + fibril_mutex_unlock(&vol->lock); + return ELIMIT; + } + + vol->hotspares[vol->hotspare_no].svc_id = hotspare; + vol->hotspares[vol->hotspare_no].status = HR_EXT_HOTSPARE; + vol->hotspare_no++; + + /* + * If the volume is degraded, start rebuild right away. + */ + if (vol->status == HR_VOL_DEGRADED) { + HR_DEBUG("hr_raid5_add_hotspare(): volume in DEGRADED state, " + "spawning new rebuild fibril\n"); + fid_t fib = fibril_create(hr_raid5_rebuild, vol); + if (fib == 0) + return EINVAL; + fibril_start(fib); + fibril_detach(fib); + } + + fibril_mutex_unlock(&vol->lock); + + return EOK; +} + static errno_t hr_raid5_bd_open(bd_srvs_t *bds, bd_srv_t *bd) { HR_DEBUG("hr_bd_open()\n"); @@ -224,11 +261,21 @@ static errno_t hr_raid5_update_vol_status(hr_volume_t *vol) } return EOK; case 1: - if (old_state != HR_VOL_DEGRADED) { + if (old_state != HR_VOL_DEGRADED && + old_state != HR_VOL_REBUILD) { HR_WARN("RAID 5 array \"%s\" (%lu) has 1 extent " "inactive, marking as DEGRADED", vol->devname, vol->svc_id); vol->status = HR_VOL_DEGRADED; + if (vol->hotspare_no > 0) { + fid_t fib = fibril_create(hr_raid5_rebuild, + vol); + if (fib == 0) { + return EINVAL; + } + fibril_start(fib); + fibril_detach(fib); + } } return EOK; default: @@ -242,6 +289,15 @@ static errno_t hr_raid5_update_vol_status(hr_volume_t *vol) } } +static void hr_raid5_handle_extent_error(hr_volume_t *vol, size_t extent, + errno_t rc) +{ + if (rc == ENOENT) + hr_update_ext_status(vol, extent, HR_EXT_MISSING); + else if (rc != EOK) + hr_update_ext_status(vol, extent, HR_EXT_FAILED); +} + static void xor(void *dst, const void *src, size_t size) { size_t i; @@ -513,10 +569,7 @@ static errno_t hr_raid5_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, if (rc == ENOMEM) goto error; - if (rc == ENOENT) - hr_update_ext_status(vol, extent, HR_EXT_MISSING); - else if (rc != EOK) - hr_update_ext_status(vol, extent, HR_EXT_FAILED); + hr_raid5_handle_extent_error(vol, extent, rc); if (rc != EOK) { rc = hr_raid5_update_vol_status(vol); @@ -557,5 +610,138 @@ static errno_t hr_raid5_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, return rc; } +static errno_t hr_raid5_rebuild(void *arg) +{ + HR_DEBUG("hr_raid5_rebuild()\n"); + + hr_volume_t *vol = arg; + errno_t rc = EOK; + void *buf = NULL, *xorbuf = NULL; + + fibril_mutex_lock(&vol->lock); + + if (vol->hotspare_no == 0) { + HR_WARN("hr_raid5_rebuild(): no free hotspares on \"%s\", " + "aborting rebuild\n", vol->devname); + /* retval isn't checked for now */ + goto end; + } + + size_t bad = vol->dev_no; + for (size_t i = 0; i < vol->dev_no; i++) { + if (vol->extents[i].status == HR_EXT_FAILED) { + bad = i; + break; + } + } + + if (bad == vol->dev_no) { + HR_WARN("hr_raid5_rebuild(): no bad extent on \"%s\", " + "aborting rebuild\n", vol->devname); + /* retval isn't checked for now */ + goto end; + } + + block_fini(vol->extents[bad].svc_id); + + size_t hotspare_idx = vol->hotspare_no - 1; + + vol->extents[bad].svc_id = vol->hotspares[hotspare_idx].svc_id; + hr_update_ext_status(vol, bad, HR_EXT_REBUILD); + + vol->hotspares[hotspare_idx].svc_id = 0; + vol->hotspares[hotspare_idx].status = HR_EXT_MISSING; + vol->hotspare_no--; + + HR_WARN("hr_raid5_rebuild(): changing volume \"%s\" (%lu) state " + "from %s to %s\n", vol->devname, vol->svc_id, + hr_get_vol_status_msg(vol->status), + hr_get_vol_status_msg(HR_VOL_REBUILD)); + vol->status = HR_VOL_REBUILD; + + hr_extent_t *hotspare = &vol->extents[bad]; + + HR_DEBUG("hr_raid5_rebuild(): initing (%lu)\n", hotspare->svc_id); + + rc = block_init(hotspare->svc_id); + if (rc != EOK) { + HR_ERROR("hr_raid5_rebuild(): initing (%lu) failed, " + "aborting rebuild\n", hotspare->svc_id); + goto end; + } + + uint64_t max_blks = DATA_XFER_LIMIT / vol->bsize; + uint64_t left = vol->data_blkno / (vol->dev_no - 1); + buf = malloc(max_blks * vol->bsize); + xorbuf = malloc(max_blks * vol->bsize); + + uint64_t ba = 0, cnt; + hr_add_ba_offset(vol, &ba); + while (left != 0) { + cnt = min(left, max_blks); + + /* + * Almost the same as read_degraded, + * but we don't want to allocate new + * xorbuf each blk rebuild batch. + */ + bool first = true; + for (size_t i = 0; i < vol->dev_no; i++) { + if (i == bad) + continue; + rc = block_read_direct(vol->extents[i].svc_id, ba, cnt, + buf); + if (rc != EOK) { + hr_raid5_handle_extent_error(vol, i, rc); + HR_ERROR("rebuild on \"%s\" (%lu), failed due " + "to a failed ONLINE extent, number %lu\n", + vol->devname, vol->svc_id, i); + goto end; + } + + if (first) + memcpy(xorbuf, buf, cnt * vol->bsize); + else + xor(xorbuf, buf, cnt * vol->bsize); + + first = false; + } + + rc = block_write_direct(hotspare->svc_id, ba, cnt, xorbuf); + if (rc != EOK) { + hr_raid5_handle_extent_error(vol, bad, rc); + HR_ERROR("rebuild on \"%s\" (%lu), failed due to " + "the rebuilt extent number %lu failing\n", + vol->devname, vol->svc_id, bad); + goto end; + } + + ba += cnt; + left -= cnt; + } + + HR_DEBUG("hr_raid5_rebuild(): rebuild finished on \"%s\" (%lu), " + "extent number %lu\n", vol->devname, vol->svc_id, hotspare_idx); + + hr_update_ext_status(vol, bad, HR_EXT_ONLINE); + /* + * For now write metadata at the end, because + * we don't sync metada accross extents yet. + */ + hr_write_meta_to_ext(vol, bad); +end: + (void) hr_raid5_update_vol_status(vol); + + fibril_mutex_unlock(&vol->lock); + + if (buf != NULL) + free(buf); + + if (xorbuf != NULL) + free(xorbuf); + + return rc; +} + /** @} */ diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index c5502acb1b..730f9f4d9e 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -106,6 +106,7 @@ extern void hr_raid5_status_event(hr_volume_t *); extern errno_t hr_raid1_add_hotspare(hr_volume_t *, service_id_t); extern errno_t hr_raid4_add_hotspare(hr_volume_t *, service_id_t); +extern errno_t hr_raid5_add_hotspare(hr_volume_t *, service_id_t); #endif From bf0a79165b9ed48ab71bc06b9cc9a53949a8c8ed Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Wed, 27 Nov 2024 12:19:10 +0100 Subject: [PATCH 081/324] hr: cstyle --- uspace/app/hrctl/hrctl.c | 2 +- uspace/srv/bd/hr/hr.c | 2 +- uspace/srv/bd/hr/raid0.c | 4 ++-- uspace/srv/bd/hr/raid1.c | 6 +++--- uspace/srv/bd/hr/raid4.c | 12 ++++++------ uspace/srv/bd/hr/raid5.c | 12 ++++++------ uspace/srv/bd/hr/superblock.c | 2 +- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index c07d274e2d..656981131f 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -340,7 +340,7 @@ int main(int argc, char **argv) break; case 'n': cfg->dev_no = strtol(optarg, NULL, 10); - if ((int) cfg->dev_no + optind != argc) + if ((int)cfg->dev_no + optind != argc) goto bad; rc = fill_config_devs(argc, argv, optind, cfg); if (rc != EOK) { diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 26de98aa3a..fe97cc318d 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -263,7 +263,7 @@ static void hr_stop_srv(ipc_call_t *icall) hr_volume_t *vol; svc_id = ipc_get_arg1(icall); - fail_extent = (long) ipc_get_arg2(icall); + fail_extent = (long)ipc_get_arg2(icall); vol = hr_get_volume(svc_id); if (vol == NULL) { diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index 1101b25610..8b2c4c0bb6 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -127,7 +127,7 @@ errno_t hr_raid0_init(hr_volume_t *vol) void hr_raid0_status_event(hr_volume_t *vol) { fibril_mutex_lock(&vol->lock); - (void) hr_raid0_update_vol_status(vol); + (void)hr_raid0_update_vol_status(vol); fibril_mutex_unlock(&vol->lock); } @@ -290,7 +290,7 @@ static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, } error: - (void) hr_raid0_update_vol_status(vol); + (void)hr_raid0_update_vol_status(vol); fibril_mutex_unlock(&vol->lock); return rc; } diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 4c359fa5a8..8041d7579d 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -128,7 +128,7 @@ errno_t hr_raid1_init(hr_volume_t *vol) void hr_raid1_status_event(hr_volume_t *vol) { fibril_mutex_lock(&vol->lock); - (void) hr_raid1_update_vol_status(vol); + (void)hr_raid1_update_vol_status(vol); fibril_mutex_unlock(&vol->lock); } @@ -358,7 +358,7 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, else rc = EIO; - (void) hr_raid1_update_vol_status(vol); + (void)hr_raid1_update_vol_status(vol); fibril_mutex_unlock(&vol->lock); return rc; } @@ -485,7 +485,7 @@ static errno_t hr_raid1_rebuild(void *arg) */ hr_write_meta_to_ext(vol, bad); end: - (void) hr_raid1_update_vol_status(vol); + (void)hr_raid1_update_vol_status(vol); fibril_mutex_unlock(&vol->lock); diff --git a/uspace/srv/bd/hr/raid4.c b/uspace/srv/bd/hr/raid4.c index d8dc291805..1e0836e2d3 100644 --- a/uspace/srv/bd/hr/raid4.c +++ b/uspace/srv/bd/hr/raid4.c @@ -142,7 +142,7 @@ errno_t hr_raid4_init(hr_volume_t *vol) void hr_raid4_status_event(hr_volume_t *vol) { fibril_mutex_lock(&vol->lock); - (void) hr_raid4_update_vol_status(vol); + (void)hr_raid4_update_vol_status(vol); fibril_mutex_unlock(&vol->lock); } @@ -386,7 +386,7 @@ static errno_t hr_raid4_write(hr_volume_t *vol, uint64_t extent, aoff64_t ba, return ENOMEM; } - if (extent == (size_t) bad) { + if (extent == (size_t)bad) { /* * new parity = read other and xor in new data * @@ -394,7 +394,7 @@ static errno_t hr_raid4_write(hr_volume_t *vol, uint64_t extent, aoff64_t ba, */ memset(xorbuf, 0, len); for (i = 1; i < vol->dev_no; i++) { - if (i == (size_t) bad) { + if (i == (size_t)bad) continue; } else { rc = block_read_direct(vol->extents[i].svc_id, @@ -544,7 +544,7 @@ static errno_t hr_raid4_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, case HR_BD_READ: retry_read: ssize_t bad = hr_raid4_get_bad_ext(vol); - if (bad > 0 && extent == (size_t) bad) { + if (bad > 0 && extent == (size_t)bad) { rc = hr_raid4_read_degraded(vol, bad, phys_block, data_read, cnt); } else { @@ -599,7 +599,7 @@ static errno_t hr_raid4_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, } error: - (void) hr_raid4_update_vol_status(vol); + (void)hr_raid4_update_vol_status(vol); fibril_mutex_unlock(&vol->lock); return rc; } @@ -724,7 +724,7 @@ static errno_t hr_raid4_rebuild(void *arg) */ hr_write_meta_to_ext(vol, bad); end: - (void) hr_raid4_update_vol_status(vol); + (void)hr_raid4_update_vol_status(vol); fibril_mutex_unlock(&vol->lock); diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 8faac5763a..252e6415ae 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -139,7 +139,7 @@ errno_t hr_raid5_init(hr_volume_t *vol) void hr_raid5_status_event(hr_volume_t *vol) { fibril_mutex_lock(&vol->lock); - (void) hr_raid5_update_vol_status(vol); + (void)hr_raid5_update_vol_status(vol); fibril_mutex_unlock(&vol->lock); } @@ -384,7 +384,7 @@ static errno_t hr_raid5_write(hr_volume_t *vol, uint64_t p_extent, return ENOMEM; } - if (extent == (size_t) bad) { + if (extent == (size_t)bad) { /* * new parity = read other and xor in new data * @@ -392,7 +392,7 @@ static errno_t hr_raid5_write(hr_volume_t *vol, uint64_t p_extent, */ memset(xorbuf, 0, len); for (i = 1; i < vol->dev_no; i++) { - if (i == (size_t) bad) { + if (i == (size_t)bad) continue; } else { rc = block_read_direct(vol->extents[i].svc_id, @@ -546,7 +546,7 @@ static errno_t hr_raid5_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, case HR_BD_READ: retry_read: ssize_t bad = hr_raid5_get_bad_ext(vol); - if (bad > 0 && extent == (size_t) bad) { + if (bad > 0 && extent == (size_t)bad) { rc = hr_raid5_read_degraded(vol, bad, phys_block, data_read, cnt); } else { @@ -605,7 +605,7 @@ static errno_t hr_raid5_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, } error: - (void) hr_raid5_update_vol_status(vol); + (void)hr_raid5_update_vol_status(vol); fibril_mutex_unlock(&vol->lock); return rc; } @@ -730,7 +730,7 @@ static errno_t hr_raid5_rebuild(void *arg) */ hr_write_meta_to_ext(vol, bad); end: - (void) hr_raid5_update_vol_status(vol); + (void)hr_raid5_update_vol_status(vol); fibril_mutex_unlock(&vol->lock); diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index dfb69e065c..f6c3b5e91f 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -211,7 +211,7 @@ errno_t hr_fill_vol_from_meta(hr_volume_t *vol) /* sort */ for (size_t i = 0; i < vol->dev_no; i++) { for (size_t j = 0; j < vol->dev_no; j++) { - if (i == (uint32_t) md_order[j]) { + if (i == (uint32_t)md_order[j]) { vol->extents[i].svc_id = cfg_svc_id_order[j]; vol->extents[i].status = HR_EXT_ONLINE; } From 8160e4c03f7a3122876610eeeb0b4d480a75452b Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Wed, 27 Nov 2024 13:58:10 +0100 Subject: [PATCH 082/324] hr: RAID 4,5: optimize operations with xorbuf Read block on first iteration directly to xorbuf. This way one memset and one xor is saved. --- uspace/srv/bd/hr/raid4.c | 54 ++++++++++++++++++++++++------- uspace/srv/bd/hr/raid5.c | 68 +++++++++++++++++++++++++++++----------- 2 files changed, 93 insertions(+), 29 deletions(-) diff --git a/uspace/srv/bd/hr/raid4.c b/uspace/srv/bd/hr/raid4.c index 1e0836e2d3..6592a3b1fd 100644 --- a/uspace/srv/bd/hr/raid4.c +++ b/uspace/srv/bd/hr/raid4.c @@ -331,15 +331,24 @@ static errno_t hr_raid4_read_degraded(hr_volume_t *vol, uint64_t bad, } /* read all other extents in the stripe */ - memset(xorbuf, 0, len); + bool first = true; for (i = 0; i < vol->dev_no; i++) { - if (i == bad) { + if (i == bad) continue; + + if (first) { + rc = block_read_direct(vol->extents[i].svc_id, block, + cnt, xorbuf); + if (rc != EOK) + goto end; + + first = false; } else { rc = block_read_direct(vol->extents[i].svc_id, block, cnt, buf); if (rc != EOK) goto end; + xor(xorbuf, buf, len); } } @@ -392,15 +401,24 @@ static errno_t hr_raid4_write(hr_volume_t *vol, uint64_t extent, aoff64_t ba, * * write new parity */ - memset(xorbuf, 0, len); + bool first = true; for (i = 1; i < vol->dev_no; i++) { if (i == (size_t)bad) continue; + + if (first) { + rc = block_read_direct(vol->extents[i].svc_id, + ba, cnt, xorbuf); + if (rc != EOK) + goto end; + + first = false; } else { rc = block_read_direct(vol->extents[i].svc_id, ba, cnt, buf); if (rc != EOK) goto end; + xor(xorbuf, buf, len); } } @@ -466,16 +484,30 @@ static errno_t hr_raid4_write_parity(hr_volume_t *vol, uint64_t extent, * * XXX: subtract method */ - memset(xorbuf, 0, len); + bool first = true; for (i = 1; i < vol->dev_no; i++) { - if (i == extent) { - xor(xorbuf, data, len); + if (first) { + if (i == extent) { + memcpy(xorbuf, data, len); + } else { + rc = block_read_direct(vol->extents[i].svc_id, + block, cnt, xorbuf); + if (rc != EOK) + goto end; + } + + first = false; } else { - rc = block_read_direct(vol->extents[i].svc_id, block, - cnt, buf); - if (rc != EOK) - goto end; - xor(xorbuf, buf, len); + if (i == extent) { + xor(xorbuf, data, len); + } else { + rc = block_read_direct(vol->extents[i].svc_id, + block, cnt, buf); + if (rc != EOK) + goto end; + + xor(xorbuf, buf, len); + } } } diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 252e6415ae..02e36000e8 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -328,10 +328,18 @@ static errno_t hr_raid5_read_degraded(hr_volume_t *vol, uint64_t bad, } /* read all other extents in the stripe */ - memset(xorbuf, 0, len); + bool first = true; for (i = 0; i < vol->dev_no; i++) { - if (i == bad) { + if (i == bad) continue; + + if (first) { + rc = block_read_direct(vol->extents[i].svc_id, block, + cnt, xorbuf); + if (rc != EOK) + goto end; + + first = false; } else { rc = block_read_direct(vol->extents[i].svc_id, block, cnt, buf); @@ -390,10 +398,17 @@ static errno_t hr_raid5_write(hr_volume_t *vol, uint64_t p_extent, * * write new parity */ - memset(xorbuf, 0, len); + bool first = true; for (i = 1; i < vol->dev_no; i++) { if (i == (size_t)bad) continue; + if (first) { + rc = block_read_direct(vol->extents[i].svc_id, + ba, cnt, xorbuf); + if (rc != EOK) + goto end; + + first = false; } else { rc = block_read_direct(vol->extents[i].svc_id, ba, cnt, buf); @@ -460,18 +475,33 @@ static errno_t hr_raid5_write_parity(hr_volume_t *vol, uint64_t p_extent, return ENOMEM; } - memset(xorbuf, 0, len); + bool first = true; for (i = 0; i < vol->dev_no; i++) { if (i == p_extent) continue; - if (i == extent) { - xor(xorbuf, data, len); + + if (first) { + if (i == extent) { + memcpy(xorbuf, data, len); + } else { + rc = block_read_direct(vol->extents[i].svc_id, + block, cnt, xorbuf); + if (rc != EOK) + goto end; + } + + first = false; } else { - rc = block_read_direct(vol->extents[i].svc_id, - block, cnt, buf); - if (rc != EOK) - goto end; - xor(xorbuf, buf, len); + if (i == extent) { + xor(xorbuf, data, len); + } else { + rc = block_read_direct(vol->extents[i].svc_id, + block, cnt, buf); + if (rc != EOK) + goto end; + + xor(xorbuf, buf, len); + } } } @@ -689,8 +719,12 @@ static errno_t hr_raid5_rebuild(void *arg) for (size_t i = 0; i < vol->dev_no; i++) { if (i == bad) continue; - rc = block_read_direct(vol->extents[i].svc_id, ba, cnt, - buf); + if (first) + rc = block_read_direct(vol->extents[i].svc_id, + ba, cnt, xorbuf); + else + rc = block_read_direct(vol->extents[i].svc_id, + ba, cnt, buf); if (rc != EOK) { hr_raid5_handle_extent_error(vol, i, rc); HR_ERROR("rebuild on \"%s\" (%lu), failed due " @@ -699,12 +733,10 @@ static errno_t hr_raid5_rebuild(void *arg) goto end; } - if (first) - memcpy(xorbuf, buf, cnt * vol->bsize); - else + if (!first) xor(xorbuf, buf, cnt * vol->bsize); - - first = false; + else + first = false; } rc = block_write_direct(hotspare->svc_id, ba, cnt, xorbuf); From 40bf2c63e51340f51bf468445a6cdbf6557c8840 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Wed, 27 Nov 2024 14:28:59 +0100 Subject: [PATCH 083/324] hr: allow IO requests to be served during rebuild --- uspace/srv/bd/hr/raid1.c | 7 +++++++ uspace/srv/bd/hr/raid4.c | 10 +++++++++- uspace/srv/bd/hr/raid5.c | 10 +++++++++- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 8041d7579d..685b959ee1 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -473,6 +473,13 @@ static errno_t hr_raid1_rebuild(void *arg) ba += cnt; left -= cnt; + + /* + * Let other IO requests be served + * during rebuild. + */ + fibril_mutex_unlock(&vol->lock); + fibril_mutex_lock(&vol->lock); } HR_DEBUG("hr_raid1_rebuild(): rebuild finished on \"%s\" (%lu), " diff --git a/uspace/srv/bd/hr/raid4.c b/uspace/srv/bd/hr/raid4.c index 6592a3b1fd..d26e180b4a 100644 --- a/uspace/srv/bd/hr/raid4.c +++ b/uspace/srv/bd/hr/raid4.c @@ -229,7 +229,8 @@ static errno_t hr_raid4_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb) static errno_t hr_raid4_vol_usable(hr_volume_t *vol) { if (vol->status == HR_VOL_ONLINE || - vol->status == HR_VOL_DEGRADED) + vol->status == HR_VOL_DEGRADED || + vol->status == HR_VOL_REBUILD) return EOK; return EINVAL; } @@ -744,6 +745,13 @@ static errno_t hr_raid4_rebuild(void *arg) ba += cnt; left -= cnt; + + /* + * Let other IO requests be served + * during rebuild. + */ + fibril_mutex_unlock(&vol->lock); + fibril_mutex_lock(&vol->lock); } HR_DEBUG("hr_raid4_rebuild(): rebuild finished on \"%s\" (%lu), " diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 02e36000e8..610283b685 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -226,7 +226,8 @@ static errno_t hr_raid5_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb) static errno_t hr_raid5_vol_usable(hr_volume_t *vol) { if (vol->status == HR_VOL_ONLINE || - vol->status == HR_VOL_DEGRADED) + vol->status == HR_VOL_DEGRADED || + vol->status == HR_VOL_REBUILD) return EOK; return EINVAL; } @@ -750,6 +751,13 @@ static errno_t hr_raid5_rebuild(void *arg) ba += cnt; left -= cnt; + + /* + * Let other IO requests be served + * during rebuild. + */ + fibril_mutex_unlock(&vol->lock); + fibril_mutex_lock(&vol->lock); } HR_DEBUG("hr_raid5_rebuild(): rebuild finished on \"%s\" (%lu), " From 65706f1dd3b78368b8130173b8caeeba0642c1ba Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Wed, 27 Nov 2024 15:06:41 +0100 Subject: [PATCH 084/324] hr: rename dev_no -> extent_no in hr_volume_t --- uspace/srv/bd/hr/hr.c | 4 +-- uspace/srv/bd/hr/raid0.c | 12 ++++----- uspace/srv/bd/hr/raid1.c | 22 ++++++++-------- uspace/srv/bd/hr/raid4.c | 32 +++++++++++------------ uspace/srv/bd/hr/raid5.c | 48 +++++++++++++++++------------------ uspace/srv/bd/hr/superblock.c | 20 +++++++-------- uspace/srv/bd/hr/util.c | 12 ++++----- uspace/srv/bd/hr/var.h | 2 +- 8 files changed, 76 insertions(+), 76 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index fe97cc318d..4198cc549d 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -158,7 +158,7 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) for (i = 0; i < cfg->dev_no; i++) new_volume->extents[i].svc_id = cfg->devs[i]; new_volume->level = cfg->level; - new_volume->dev_no = cfg->dev_no; + new_volume->extent_no = cfg->dev_no; if (assemble) { if (cfg->level != HR_LVL_UNKNOWN) @@ -353,7 +353,7 @@ static void hr_print_status_srv(ipc_call_t *icall) memcpy(info.hotspares, vol->hotspares, sizeof(hr_extent_t) * HR_MAX_HOTSPARES); info.svc_id = vol->svc_id; - info.extent_no = vol->dev_no; + info.extent_no = vol->extent_no; info.hotspare_no = vol->hotspare_no; info.level = vol->level; /* print usable number of blocks */ diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index 8b2c4c0bb6..197c1ebfaf 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -85,7 +85,7 @@ errno_t hr_raid0_create(hr_volume_t *new_volume) assert(new_volume->level == HR_LVL_0); - if (new_volume->dev_no < 2) { + if (new_volume->extent_no < 2) { HR_ERROR("RAID 0 array needs at least 2 devices\n"); return EINVAL; } @@ -118,7 +118,7 @@ errno_t hr_raid0_init(hr_volume_t *vol) vol->nblocks = total_blkno; vol->bsize = bsize; vol->data_offset = HR_DATA_OFF; - vol->data_blkno = vol->nblocks - (vol->data_offset * vol->dev_no); + vol->data_blkno = vol->nblocks - (vol->data_offset * vol->extent_no); vol->strip_size = HR_STRIP_SIZE; return EOK; @@ -189,7 +189,7 @@ static errno_t hr_raid0_check_vol_status(hr_volume_t *vol) */ static errno_t hr_raid0_update_vol_status(hr_volume_t *vol) { - for (size_t i = 0; i < vol->dev_no; i++) { + for (size_t i = 0; i < vol->extent_no; i++) { if (vol->extents[i].status != HR_EXT_ONLINE) { HR_WARN("RAID 0 needs all extents to be ONLINE, " "marking \"%s\" (%lu) as FAULTY", @@ -230,8 +230,8 @@ static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, uint64_t strip_size = vol->strip_size / vol->bsize; /* in blocks */ uint64_t stripe = ba / strip_size; /* stripe number */ - uint64_t extent = stripe % vol->dev_no; - uint64_t ext_stripe = stripe / vol->dev_no; /* stripe level */ + uint64_t extent = stripe % vol->extent_no; + uint64_t ext_stripe = stripe / vol->extent_no; /* stripe level */ uint64_t strip_off = ba % strip_size; /* strip offset */ fibril_mutex_lock(&vol->lock); @@ -283,7 +283,7 @@ static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, left -= cnt; strip_off = 0; extent++; - if (extent >= vol->dev_no) { + if (extent >= vol->extent_no) { ext_stripe++; extent = 0; } diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 685b959ee1..83c5f6b107 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -86,7 +86,7 @@ errno_t hr_raid1_create(hr_volume_t *new_volume) assert(new_volume->level == HR_LVL_1); - if (new_volume->dev_no < 2) { + if (new_volume->extent_no < 2) { HR_ERROR("RAID 1 array needs at least 2 devices\n"); return EINVAL; } @@ -116,7 +116,7 @@ errno_t hr_raid1_init(hr_volume_t *vol) if (rc != EOK) return rc; - vol->nblocks = total_blkno / vol->dev_no; + vol->nblocks = total_blkno / vol->extent_no; vol->bsize = bsize; vol->data_offset = HR_DATA_OFF; vol->data_blkno = vol->nblocks - vol->data_offset; @@ -238,7 +238,7 @@ static errno_t hr_raid1_update_vol_status(hr_volume_t *vol) vol->status = HR_VOL_FAULTY; } return EINVAL; - } else if (healthy < vol->dev_no) { + } else if (healthy < vol->extent_no) { if (old_state != HR_VOL_DEGRADED && old_state != HR_VOL_REBUILD) { HR_WARN("RAID 1 array \"%s\" (%lu) has some " @@ -304,7 +304,7 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, size_t successful = 0; switch (type) { case HR_BD_SYNC: - for (i = 0; i < vol->dev_no; i++) { + for (i = 0; i < vol->extent_no; i++) { if (vol->extents[i].status != HR_EXT_ONLINE) continue; rc = block_sync_cache(vol->extents[i].svc_id, ba, cnt); @@ -315,7 +315,7 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, } break; case HR_BD_READ: - for (i = 0; i < vol->dev_no; i++) { + for (i = 0; i < vol->extent_no; i++) { if (vol->extents[i].status != HR_EXT_ONLINE) continue; rc = block_read_direct(vol->extents[i].svc_id, ba, cnt, @@ -329,7 +329,7 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, } break; case HR_BD_WRITE: - for (i = 0; i < vol->dev_no; i++) { + for (i = 0; i < vol->extent_no; i++) { if (vol->extents[i].status != HR_EXT_ONLINE || (vol->extents[i].status == HR_EXT_REBUILD && ba >= vol->rebuild_blk)) @@ -384,15 +384,15 @@ static errno_t hr_raid1_rebuild(void *arg) goto end; } - size_t bad = vol->dev_no; - for (size_t i = 0; i < vol->dev_no; i++) { + size_t bad = vol->extent_no; + for (size_t i = 0; i < vol->extent_no; i++) { if (vol->extents[i].status == HR_EXT_FAILED) { bad = i; break; } } - if (bad == vol->dev_no) { + if (bad == vol->extent_no) { HR_WARN("hr_raid1_rebuild(): no bad extent on \"%s\", " "aborting rebuild\n", vol->devname); /* retval isn't checked for now */ @@ -440,14 +440,14 @@ static errno_t hr_raid1_rebuild(void *arg) while (left != 0) { vol->rebuild_blk = ba; cnt = min(max_blks, left); - for (size_t i = 0; i < vol->dev_no; i++) { + for (size_t i = 0; i < vol->extent_no; i++) { ext = &vol->extents[i]; if (ext->status == HR_EXT_ONLINE) { rc = block_read_direct(ext->svc_id, ba, cnt, buf); if (rc != EOK) { hr_raid1_handle_extent_error(vol, i, rc); - if (i + 1 < vol->dev_no) { + if (i + 1 < vol->extent_no) { /* still might have one ONLINE */ continue; } else { diff --git a/uspace/srv/bd/hr/raid4.c b/uspace/srv/bd/hr/raid4.c index d26e180b4a..71b91f44ea 100644 --- a/uspace/srv/bd/hr/raid4.c +++ b/uspace/srv/bd/hr/raid4.c @@ -99,7 +99,7 @@ errno_t hr_raid4_create(hr_volume_t *new_volume) assert(new_volume->level == HR_LVL_4); - if (new_volume->dev_no < 3) { + if (new_volume->extent_no < 3) { HR_ERROR("RAID 4 array needs at least 3 devices\n"); return EINVAL; } @@ -132,8 +132,8 @@ errno_t hr_raid4_init(hr_volume_t *vol) vol->nblocks = total_blkno; vol->bsize = bsize; vol->data_offset = HR_DATA_OFF; - vol->data_blkno = vol->nblocks - (vol->data_offset * vol->dev_no) - - (vol->nblocks / vol->dev_no); + vol->data_blkno = vol->nblocks - (vol->data_offset * vol->extent_no) - + (vol->nblocks / vol->extent_no); vol->strip_size = HR_STRIP_SIZE; return EOK; @@ -241,7 +241,7 @@ static errno_t hr_raid4_vol_usable(hr_volume_t *vol) */ static ssize_t hr_raid4_get_bad_ext(hr_volume_t *vol) { - for (size_t i = 0; i < vol->dev_no; i++) + for (size_t i = 0; i < vol->extent_no; i++) if (vol->extents[i].status != HR_EXT_ONLINE) return i; return -1; @@ -251,7 +251,7 @@ static errno_t hr_raid4_update_vol_status(hr_volume_t *vol) { hr_vol_status_t old_state = vol->status; size_t bad = 0; - for (size_t i = 0; i < vol->dev_no; i++) + for (size_t i = 0; i < vol->extent_no; i++) if (vol->extents[i].status != HR_EXT_ONLINE) bad++; @@ -333,7 +333,7 @@ static errno_t hr_raid4_read_degraded(hr_volume_t *vol, uint64_t bad, /* read all other extents in the stripe */ bool first = true; - for (i = 0; i < vol->dev_no; i++) { + for (i = 0; i < vol->extent_no; i++) { if (i == bad) continue; @@ -403,7 +403,7 @@ static errno_t hr_raid4_write(hr_volume_t *vol, uint64_t extent, aoff64_t ba, * write new parity */ bool first = true; - for (i = 1; i < vol->dev_no; i++) { + for (i = 1; i < vol->extent_no; i++) { if (i == (size_t)bad) continue; @@ -486,7 +486,7 @@ static errno_t hr_raid4_write_parity(hr_volume_t *vol, uint64_t extent, * XXX: subtract method */ bool first = true; - for (i = 1; i < vol->dev_no; i++) { + for (i = 1; i < vol->extent_no; i++) { if (first) { if (i == extent) { memcpy(xorbuf, data, len); @@ -546,8 +546,8 @@ static errno_t hr_raid4_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, uint64_t strip_size = vol->strip_size / vol->bsize; /* in blocks */ uint64_t stripe = (ba / strip_size); /* stripe number */ - uint64_t extent = (stripe % (vol->dev_no - 1)) + 1; - uint64_t ext_stripe = stripe / (vol->dev_no - 1); /* stripe level */ + uint64_t extent = (stripe % (vol->extent_no - 1)) + 1; + uint64_t ext_stripe = stripe / (vol->extent_no - 1); /* stripe level */ uint64_t strip_off = ba % strip_size; /* strip offset */ fibril_mutex_lock(&vol->lock); @@ -625,7 +625,7 @@ static errno_t hr_raid4_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, left -= cnt; strip_off = 0; extent++; - if (extent >= vol->dev_no) { + if (extent >= vol->extent_no) { ext_stripe++; extent = 1; } @@ -654,15 +654,15 @@ static errno_t hr_raid4_rebuild(void *arg) goto end; } - size_t bad = vol->dev_no; - for (size_t i = 0; i < vol->dev_no; i++) { + size_t bad = vol->extent_no; + for (size_t i = 0; i < vol->extent_no; i++) { if (vol->extents[i].status == HR_EXT_FAILED) { bad = i; break; } } - if (bad == vol->dev_no) { + if (bad == vol->extent_no) { HR_WARN("hr_raid4_rebuild(): no bad extent on \"%s\", " "aborting rebuild\n", vol->devname); /* retval isn't checked for now */ @@ -698,7 +698,7 @@ static errno_t hr_raid4_rebuild(void *arg) } uint64_t max_blks = DATA_XFER_LIMIT / vol->bsize; - uint64_t left = vol->data_blkno / (vol->dev_no - 1); + uint64_t left = vol->data_blkno / (vol->extent_no - 1); buf = malloc(max_blks * vol->bsize); xorbuf = malloc(max_blks * vol->bsize); @@ -713,7 +713,7 @@ static errno_t hr_raid4_rebuild(void *arg) * xorbuf each blk rebuild batch. */ bool first = true; - for (size_t i = 0; i < vol->dev_no; i++) { + for (size_t i = 0; i < vol->extent_no; i++) { if (i == bad) continue; rc = block_read_direct(vol->extents[i].svc_id, ba, cnt, diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 610283b685..fb0fdb421b 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -96,7 +96,7 @@ errno_t hr_raid5_create(hr_volume_t *new_volume) assert(new_volume->level == HR_LVL_5); - if (new_volume->dev_no < 3) { + if (new_volume->extent_no < 3) { HR_ERROR("RAID 5 array needs at least 3 devices\n"); return EINVAL; } @@ -129,8 +129,8 @@ errno_t hr_raid5_init(hr_volume_t *vol) vol->nblocks = total_blkno; vol->bsize = bsize; vol->data_offset = HR_DATA_OFF; - vol->data_blkno = vol->nblocks - (vol->data_offset * vol->dev_no) - - (vol->nblocks / vol->dev_no); + vol->data_blkno = vol->nblocks - (vol->data_offset * vol->extent_no) - + (vol->nblocks / vol->extent_no); vol->strip_size = HR_STRIP_SIZE; return EOK; @@ -238,7 +238,7 @@ static errno_t hr_raid5_vol_usable(hr_volume_t *vol) */ static ssize_t hr_raid5_get_bad_ext(hr_volume_t *vol) { - for (size_t i = 0; i < vol->dev_no; i++) + for (size_t i = 0; i < vol->extent_no; i++) if (vol->extents[i].status != HR_EXT_ONLINE) return i; return -1; @@ -248,7 +248,7 @@ static errno_t hr_raid5_update_vol_status(hr_volume_t *vol) { hr_vol_status_t old_state = vol->status; size_t bad = 0; - for (size_t i = 0; i < vol->dev_no; i++) + for (size_t i = 0; i < vol->extent_no; i++) if (vol->extents[i].status != HR_EXT_ONLINE) bad++; @@ -330,7 +330,7 @@ static errno_t hr_raid5_read_degraded(hr_volume_t *vol, uint64_t bad, /* read all other extents in the stripe */ bool first = true; - for (i = 0; i < vol->dev_no; i++) { + for (i = 0; i < vol->extent_no; i++) { if (i == bad) continue; @@ -400,7 +400,7 @@ static errno_t hr_raid5_write(hr_volume_t *vol, uint64_t p_extent, * write new parity */ bool first = true; - for (i = 1; i < vol->dev_no; i++) { + for (i = 1; i < vol->extent_no; i++) { if (i == (size_t)bad) continue; if (first) { @@ -477,7 +477,7 @@ static errno_t hr_raid5_write_parity(hr_volume_t *vol, uint64_t p_extent, } bool first = true; - for (i = 0; i < vol->dev_no; i++) { + for (i = 0; i < vol->extent_no; i++) { if (i == p_extent) continue; @@ -541,13 +541,13 @@ static errno_t hr_raid5_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, uint64_t strip_size = vol->strip_size / vol->bsize; /* in blocks */ uint64_t stripe = (ba / strip_size); /* stripe number */ - uint64_t p_extent = (stripe / (vol->dev_no - 1)) % vol->dev_no; /* parity extent */ + uint64_t p_extent = (stripe / (vol->extent_no - 1)) % vol->extent_no; /* parity extent */ uint64_t extent; - if ((stripe % (vol->dev_no - 1)) < p_extent) - extent = (stripe % (vol->dev_no - 1)); + if ((stripe % (vol->extent_no - 1)) < p_extent) + extent = (stripe % (vol->extent_no - 1)); else - extent = ((stripe % (vol->dev_no - 1)) + 1); - uint64_t ext_stripe = stripe / (vol->dev_no - 1); /* stripe level */ + extent = ((stripe % (vol->extent_no - 1)) + 1); + uint64_t ext_stripe = stripe / (vol->extent_no - 1); /* stripe level */ uint64_t strip_off = ba % strip_size; /* strip offset */ fibril_mutex_lock(&vol->lock); @@ -624,15 +624,15 @@ static errno_t hr_raid5_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, left -= cnt; strip_off = 0; - if (extent + 1 >= vol->dev_no || - (extent + 1 == p_extent && p_extent + 1 >= vol->dev_no)) + if (extent + 1 >= vol->extent_no || + (extent + 1 == p_extent && p_extent + 1 >= vol->extent_no)) ext_stripe++; stripe++; - p_extent = (stripe / (vol->dev_no - 1)) % vol->dev_no; /* parity extent */ - if ((stripe % (vol->dev_no - 1)) < p_extent) - extent = (stripe % (vol->dev_no - 1)); + p_extent = (stripe / (vol->extent_no - 1)) % vol->extent_no; /* parity extent */ + if ((stripe % (vol->extent_no - 1)) < p_extent) + extent = (stripe % (vol->extent_no - 1)); else - extent = ((stripe % (vol->dev_no - 1)) + 1); + extent = ((stripe % (vol->extent_no - 1)) + 1); } error: @@ -658,15 +658,15 @@ static errno_t hr_raid5_rebuild(void *arg) goto end; } - size_t bad = vol->dev_no; - for (size_t i = 0; i < vol->dev_no; i++) { + size_t bad = vol->extent_no; + for (size_t i = 0; i < vol->extent_no; i++) { if (vol->extents[i].status == HR_EXT_FAILED) { bad = i; break; } } - if (bad == vol->dev_no) { + if (bad == vol->extent_no) { HR_WARN("hr_raid5_rebuild(): no bad extent on \"%s\", " "aborting rebuild\n", vol->devname); /* retval isn't checked for now */ @@ -702,7 +702,7 @@ static errno_t hr_raid5_rebuild(void *arg) } uint64_t max_blks = DATA_XFER_LIMIT / vol->bsize; - uint64_t left = vol->data_blkno / (vol->dev_no - 1); + uint64_t left = vol->data_blkno / (vol->extent_no - 1); buf = malloc(max_blks * vol->bsize); xorbuf = malloc(max_blks * vol->bsize); @@ -717,7 +717,7 @@ static errno_t hr_raid5_rebuild(void *arg) * xorbuf each blk rebuild batch. */ bool first = true; - for (size_t i = 0; i < vol->dev_no; i++) { + for (size_t i = 0; i < vol->extent_no; i++) { if (i == bad) continue; if (first) diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index f6c3b5e91f..61ccd83433 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -69,7 +69,7 @@ errno_t hr_write_meta_to_vol(hr_volume_t *vol) if (rc != EOK) goto error; - for (i = 0; i < vol->dev_no; i++) { + for (i = 0; i < vol->extent_no; i++) { metadata->index = host2uint32_t_le(i); rc = uuid_generate(&uuid); @@ -137,7 +137,7 @@ static errno_t hr_fill_meta_from_vol(hr_volume_t *vol, hr_metadata_t *metadata) meta_blkno = (HR_META_OFF + HR_META_SIZE); if (vol->level != HR_LVL_1) - meta_blkno *= vol->dev_no; + meta_blkno *= vol->extent_no; if (vol->nblocks < meta_blkno) { HR_ERROR("hr_fill_meta_from_vol(): volume \"%s\" does not " @@ -152,7 +152,7 @@ static errno_t hr_fill_meta_from_vol(hr_volume_t *vol, hr_metadata_t *metadata) } metadata->magic = host2uint64_t_le(HR_MAGIC); - metadata->extent_no = host2uint32_t_le(vol->dev_no); + metadata->extent_no = host2uint32_t_le(vol->extent_no); metadata->level = host2uint32_t_le(vol->level); metadata->nblocks = host2uint64_t_le(vol->nblocks); metadata->data_blkno = host2uint64_t_le(vol->data_blkno); @@ -185,11 +185,11 @@ errno_t hr_fill_vol_from_meta(hr_volume_t *vol) return ENOMEM; service_id_t cfg_svc_id_order[HR_MAX_EXTENTS] = { 0 }; - for (size_t i = 0; i < vol->dev_no; i++) + for (size_t i = 0; i < vol->extent_no; i++) cfg_svc_id_order[i] = vol->extents[i].svc_id; int32_t md_order[HR_MAX_EXTENTS] = { 0 }; - for (size_t i = 0; i < vol->dev_no; i++) { + for (size_t i = 0; i < vol->extent_no; i++) { if (cfg_svc_id_order[i] == 0) { md_order[i] = -1; continue; @@ -203,14 +203,14 @@ errno_t hr_fill_vol_from_meta(hr_volume_t *vol) md_order[i] = uint32_t_le2host(metadata->index); } - for (size_t i = 0; i < vol->dev_no; i++) { + for (size_t i = 0; i < vol->extent_no; i++) { vol->extents[i].svc_id = 0; vol->extents[i].status = HR_EXT_MISSING; } /* sort */ - for (size_t i = 0; i < vol->dev_no; i++) { - for (size_t j = 0; j < vol->dev_no; j++) { + for (size_t i = 0; i < vol->extent_no; i++) { + for (size_t j = 0; j < vol->extent_no; j++) { if (i == (uint32_t)md_order[j]) { vol->extents[i].svc_id = cfg_svc_id_order[j]; vol->extents[i].status = HR_EXT_ONLINE; @@ -222,10 +222,10 @@ errno_t hr_fill_vol_from_meta(hr_volume_t *vol) * still assume metadata are in sync across extents */ - if (vol->dev_no != uint32_t_le2host(metadata->extent_no)) { + if (vol->extent_no != uint32_t_le2host(metadata->extent_no)) { HR_ERROR("number of divices in array differ: specified %zu, " "metadata states %u", - vol->dev_no, uint32_t_le2host(metadata->extent_no)); + vol->extent_no, uint32_t_le2host(metadata->extent_no)); rc = EINVAL; goto end; } diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 6ed7862dc3..1a01d90d6d 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -55,7 +55,7 @@ errno_t hr_init_devs(hr_volume_t *vol) size_t i; hr_extent_t *extent; - for (i = 0; i < vol->dev_no; i++) { + for (i = 0; i < vol->extent_no; i++) { extent = &vol->extents[i]; if (extent->svc_id == 0) { extent->status = HR_EXT_MISSING; @@ -83,7 +83,7 @@ void hr_fini_devs(hr_volume_t *vol) size_t i; - for (i = 0; i < vol->dev_no; i++) { + for (i = 0; i < vol->extent_no; i++) { if (vol->extents[i].status != HR_EXT_MISSING) { HR_DEBUG("hr_fini_devs(): block_fini() on (%lu)\n", vol->extents[i].svc_id); @@ -145,7 +145,7 @@ errno_t hr_check_devs(hr_volume_t *vol, uint64_t *rblkno, size_t *rbsize) uint64_t total_blocks = 0; hr_extent_t *extent; - for (i = 0; i < vol->dev_no; i++) { + for (i = 0; i < vol->extent_no; i++) { extent = &vol->extents[i]; if (extent->status == HR_EXT_MISSING) continue; @@ -162,7 +162,7 @@ errno_t hr_check_devs(hr_volume_t *vol, uint64_t *rblkno, size_t *rbsize) last_nblocks = nblocks; } - for (i = 0; i < vol->dev_no; i++) { + for (i = 0; i < vol->extent_no; i++) { extent = &vol->extents[i]; if (extent->status == HR_EXT_MISSING) continue; @@ -222,7 +222,7 @@ void hr_sync_all_extents(hr_volume_t *vol) errno_t rc; fibril_mutex_lock(&vol->lock); - for (size_t i = 0; i < vol->dev_no; i++) { + for (size_t i = 0; i < vol->extent_no; i++) { if (vol->extents[i].status != HR_EXT_ONLINE) continue; rc = block_sync_cache(vol->extents[i].svc_id, 0, 0); @@ -239,7 +239,7 @@ void hr_sync_all_extents(hr_volume_t *vol) size_t hr_count_extents(hr_volume_t *vol, hr_ext_status_t status) { size_t count = 0; - for (size_t i = 0; i < vol->dev_no; i++) { + for (size_t i = 0; i < vol->extent_no; i++) { if (vol->extents[i].status == status) count++; } diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index 730f9f4d9e..9bd3afe6a2 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -60,7 +60,7 @@ typedef struct hr_volume { link_t lvolumes; fibril_mutex_t lock; - size_t dev_no; + size_t extent_no; hr_extent_t extents[HR_MAX_EXTENTS]; size_t hotspare_no; From a0c3080f8d662e94f980dedc844200d3cc0674f5 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Thu, 28 Nov 2024 18:09:52 +0100 Subject: [PATCH 085/324] hr: util: hotspare and volume change state functions --- uspace/srv/bd/hr/raid0.c | 17 ++++---- uspace/srv/bd/hr/raid1.c | 90 ++++++++++++++++++++-------------------- uspace/srv/bd/hr/raid4.c | 80 ++++++++++++++++++----------------- uspace/srv/bd/hr/raid5.c | 80 ++++++++++++++++++----------------- uspace/srv/bd/hr/util.c | 24 +++++++++-- uspace/srv/bd/hr/util.h | 4 +- 6 files changed, 162 insertions(+), 133 deletions(-) diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index 197c1ebfaf..6aa3709870 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -180,7 +180,7 @@ static errno_t hr_raid0_check_vol_status(hr_volume_t *vol) { if (vol->status == HR_VOL_ONLINE) return EOK; - return EINVAL; + return EIO; } /* @@ -189,17 +189,19 @@ static errno_t hr_raid0_check_vol_status(hr_volume_t *vol) */ static errno_t hr_raid0_update_vol_status(hr_volume_t *vol) { + hr_vol_status_t old_state = vol->status; + for (size_t i = 0; i < vol->extent_no; i++) { if (vol->extents[i].status != HR_EXT_ONLINE) { - HR_WARN("RAID 0 needs all extents to be ONLINE, " - "marking \"%s\" (%lu) as FAULTY", - vol->devname, vol->svc_id); - vol->status = HR_VOL_FAULTY; - return EINVAL; + if (old_state != HR_VOL_FAULTY) + hr_update_vol_status(vol, HR_VOL_FAULTY); + return EIO; } } - vol->status = HR_VOL_ONLINE; + if (old_state != HR_VOL_ONLINE) + hr_update_vol_status(vol, HR_VOL_ONLINE); + return EOK; } @@ -243,6 +245,7 @@ static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, } left = cnt; + while (left != 0) { phys_block = ext_stripe * strip_size + strip_off; cnt = min(left, strip_size - strip_off); diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 83c5f6b107..387a9cf522 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -146,7 +146,8 @@ errno_t hr_raid1_add_hotspare(hr_volume_t *vol, service_id_t hotspare) } vol->hotspares[vol->hotspare_no].svc_id = hotspare; - vol->hotspares[vol->hotspare_no].status = HR_EXT_HOTSPARE; + hr_update_hotspare_status(vol, vol->hotspare_no, HR_EXT_HOTSPARE); + vol->hotspare_no++; /* @@ -157,7 +158,7 @@ errno_t hr_raid1_add_hotspare(hr_volume_t *vol, service_id_t hotspare) "spawning new rebuild fibril\n"); fid_t fib = fibril_create(hr_raid1_rebuild, vol); if (fib == 0) - return EINVAL; + return ENOMEM; fibril_start(fib); fibril_detach(fib); } @@ -218,7 +219,7 @@ static errno_t hr_raid1_check_vol_status(hr_volume_t *vol) vol->status == HR_VOL_DEGRADED || vol->status == HR_VOL_REBUILD) return EOK; - return EINVAL; + return EIO; } /* @@ -231,38 +232,28 @@ static errno_t hr_raid1_update_vol_status(hr_volume_t *vol) size_t healthy = hr_count_extents(vol, HR_EXT_ONLINE); if (healthy == 0) { - if (old_state != HR_VOL_FAULTY) { - HR_WARN("RAID 1 needs at least 1 extent to be" - "ONLINE, marking \"%s\" (%lu) volume as FAULTY", - vol->devname, vol->svc_id); - vol->status = HR_VOL_FAULTY; - } - return EINVAL; + if (old_state != HR_VOL_FAULTY) + hr_update_vol_status(vol, HR_VOL_FAULTY); + return EIO; } else if (healthy < vol->extent_no) { if (old_state != HR_VOL_DEGRADED && old_state != HR_VOL_REBUILD) { - HR_WARN("RAID 1 array \"%s\" (%lu) has some " - "unusable extent(s), marking volume as DEGRADED", - vol->devname, vol->svc_id); - vol->status = HR_VOL_DEGRADED; + + hr_update_vol_status(vol, HR_VOL_DEGRADED); + if (vol->hotspare_no > 0) { fid_t fib = fibril_create(hr_raid1_rebuild, vol); - if (fib == 0) { - return EINVAL; - } + if (fib == 0) + return ENOMEM; fibril_start(fib); fibril_detach(fib); } } return EOK; } else { - if (old_state != HR_VOL_ONLINE) { - HR_WARN("RAID 1 array \"%s\" (%lu) has all extents " - "active, marking volume as ONLINE", - vol->devname, vol->svc_id); - vol->status = HR_VOL_ONLINE; - } + if (old_state != HR_VOL_ONLINE) + hr_update_vol_status(vol, HR_VOL_ONLINE); return EOK; } } @@ -296,10 +287,8 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, fibril_mutex_lock(&vol->lock); rc = hr_raid1_check_vol_status(vol); - if (rc != EOK) { - fibril_mutex_unlock(&vol->lock); - return EIO; - } + if (rc != EOK) + goto end; size_t successful = 0; switch (type) { @@ -351,6 +340,7 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, break; default: rc = EINVAL; + goto end; } if (successful > 0) @@ -358,6 +348,7 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, else rc = EIO; +end: (void)hr_raid1_update_vol_status(vol); fibril_mutex_unlock(&vol->lock); return rc; @@ -399,44 +390,55 @@ static errno_t hr_raid1_rebuild(void *arg) goto end; } - block_fini(vol->extents[bad].svc_id); - size_t hotspare_idx = vol->hotspare_no - 1; - vol->rebuild_blk = 0; + hr_ext_status_t hs_state = vol->hotspares[hotspare_idx].status; + if (hs_state != HR_EXT_HOTSPARE) { + HR_ERROR("hr_raid1_rebuild(): invalid hotspare state \"%s\", " + "aborting rebuild\n", hr_get_ext_status_msg(hs_state)); + rc = EINVAL; + goto end; + } + + HR_DEBUG("hr_raid1_rebuild(): swapping in hotspare\n"); + + block_fini(vol->extents[bad].svc_id); + vol->extents[bad].svc_id = vol->hotspares[hotspare_idx].svc_id; - hr_update_ext_status(vol, bad, HR_EXT_REBUILD); + hr_update_ext_status(vol, bad, HR_EXT_HOTSPARE); vol->hotspares[hotspare_idx].svc_id = 0; - vol->hotspares[hotspare_idx].status = HR_EXT_MISSING; - vol->hotspare_no--; - - HR_WARN("hr_raid1_rebuild(): changing volume \"%s\" (%lu) state " - "from %s to %s\n", vol->devname, vol->svc_id, - hr_get_vol_status_msg(vol->status), - hr_get_vol_status_msg(HR_VOL_REBUILD)); - vol->status = HR_VOL_REBUILD; + hr_update_hotspare_status(vol, hotspare_idx, HR_EXT_MISSING); - hr_extent_t *hotspare = &vol->extents[bad]; + vol->hotspare_no--; - HR_DEBUG("hr_raid1_rebuild(): initing (%lu)\n", hotspare->svc_id); + hr_extent_t *rebuild_ext = &vol->extents[bad]; - rc = block_init(hotspare->svc_id); + rc = block_init(rebuild_ext->svc_id); if (rc != EOK) { HR_ERROR("hr_raid1_rebuild(): initing (%lu) failed, " - "aborting rebuild\n", hotspare->svc_id); + "aborting rebuild\n", rebuild_ext->svc_id); goto end; } + HR_DEBUG("hr_raid1_rebuild(): starting rebuild on (%lu)\n", + rebuild_ext->svc_id); + + hr_update_ext_status(vol, bad, HR_EXT_REBUILD); + hr_update_vol_status(vol, HR_VOL_REBUILD); + size_t left = vol->data_blkno; size_t max_blks = DATA_XFER_LIMIT / vol->bsize; buf = malloc(max_blks * vol->bsize); hr_extent_t *ext; + vol->rebuild_blk = 0; + size_t cnt; uint64_t ba = 0; hr_add_ba_offset(vol, &ba); + while (left != 0) { vol->rebuild_blk = ba; cnt = min(max_blks, left); @@ -461,7 +463,7 @@ static errno_t hr_raid1_rebuild(void *arg) } } - rc = block_write_direct(hotspare->svc_id, ba, cnt, buf); + rc = block_write_direct(rebuild_ext->svc_id, ba, cnt, buf); if (rc != EOK) { hr_raid1_handle_extent_error(vol, bad, rc); HR_ERROR("rebuild on \"%s\" (%lu), failed due to " diff --git a/uspace/srv/bd/hr/raid4.c b/uspace/srv/bd/hr/raid4.c index 71b91f44ea..8aee9bd27d 100644 --- a/uspace/srv/bd/hr/raid4.c +++ b/uspace/srv/bd/hr/raid4.c @@ -160,7 +160,8 @@ errno_t hr_raid4_add_hotspare(hr_volume_t *vol, service_id_t hotspare) } vol->hotspares[vol->hotspare_no].svc_id = hotspare; - vol->hotspares[vol->hotspare_no].status = HR_EXT_HOTSPARE; + hr_update_hotspare_status(vol, vol->hotspare_no, HR_EXT_HOTSPARE); + vol->hotspare_no++; /* @@ -171,7 +172,7 @@ errno_t hr_raid4_add_hotspare(hr_volume_t *vol, service_id_t hotspare) "spawning new rebuild fibril\n"); fid_t fib = fibril_create(hr_raid4_rebuild, vol); if (fib == 0) - return EINVAL; + return ENOMEM; fibril_start(fib); fibril_detach(fib); } @@ -232,7 +233,7 @@ static errno_t hr_raid4_vol_usable(hr_volume_t *vol) vol->status == HR_VOL_DEGRADED || vol->status == HR_VOL_REBUILD) return EOK; - return EINVAL; + return EIO; } /* @@ -257,39 +258,29 @@ static errno_t hr_raid4_update_vol_status(hr_volume_t *vol) switch (bad) { case 0: - if (old_state != HR_VOL_ONLINE) { - HR_WARN("RAID 4 has all extents online, " - "marking \"%s\" (%lu) as ONLINE", - vol->devname, vol->svc_id); - vol->status = HR_VOL_ONLINE; - } + if (old_state != HR_VOL_ONLINE) + hr_update_vol_status(vol, HR_VOL_ONLINE); return EOK; case 1: if (old_state != HR_VOL_DEGRADED && old_state != HR_VOL_REBUILD) { - HR_WARN("RAID 4 array \"%s\" (%lu) has 1 extent " - "inactive, marking as DEGRADED", - vol->devname, vol->svc_id); - vol->status = HR_VOL_DEGRADED; + + hr_update_vol_status(vol, HR_VOL_DEGRADED); + if (vol->hotspare_no > 0) { fid_t fib = fibril_create(hr_raid4_rebuild, vol); - if (fib == 0) { - return EINVAL; - } + if (fib == 0) + return ENOMEM; fibril_start(fib); fibril_detach(fib); } } return EOK; default: - if (old_state != HR_VOL_FAULTY) { - HR_WARN("RAID 4 array \"%s\" (%lu) has more " - "than one 1 extent unusable, marking as FAULTY", - vol->devname, vol->svc_id); - vol->status = HR_VOL_FAULTY; - } - return EINVAL; + if (old_state != HR_VOL_FAULTY) + hr_update_vol_status(vol, HR_VOL_FAULTY); + return EIO; } } @@ -559,6 +550,7 @@ static errno_t hr_raid4_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, } left = cnt; + while (left != 0) { phys_block = ext_stripe * strip_size + strip_off; cnt = min(left, strip_size - strip_off); @@ -669,34 +661,43 @@ static errno_t hr_raid4_rebuild(void *arg) goto end; } - block_fini(vol->extents[bad].svc_id); - size_t hotspare_idx = vol->hotspare_no - 1; + hr_ext_status_t hs_state = vol->hotspares[hotspare_idx].status; + if (hs_state != HR_EXT_HOTSPARE) { + HR_ERROR("hr_raid4_rebuild(): invalid hotspare state \"%s\", " + "aborting rebuild\n", hr_get_ext_status_msg(hs_state)); + rc = EINVAL; + goto end; + } + + HR_DEBUG("hr_raid4_rebuild(): swapping in hotspare\n"); + + block_fini(vol->extents[bad].svc_id); + vol->extents[bad].svc_id = vol->hotspares[hotspare_idx].svc_id; - hr_update_ext_status(vol, bad, HR_EXT_REBUILD); + hr_update_ext_status(vol, bad, HR_EXT_HOTSPARE); vol->hotspares[hotspare_idx].svc_id = 0; - vol->hotspares[hotspare_idx].status = HR_EXT_MISSING; - vol->hotspare_no--; + hr_update_hotspare_status(vol, hotspare_idx, HR_EXT_MISSING); - HR_WARN("hr_raid4_rebuild(): changing volume \"%s\" (%lu) state " - "from %s to %s\n", vol->devname, vol->svc_id, - hr_get_vol_status_msg(vol->status), - hr_get_vol_status_msg(HR_VOL_REBUILD)); - vol->status = HR_VOL_REBUILD; - - hr_extent_t *hotspare = &vol->extents[bad]; + vol->hotspare_no--; - HR_DEBUG("hr_raid4_rebuild(): initing (%lu)\n", hotspare->svc_id); + hr_extent_t *rebuild_ext = &vol->extents[bad]; - rc = block_init(hotspare->svc_id); + rc = block_init(rebuild_ext->svc_id); if (rc != EOK) { HR_ERROR("hr_raid4_rebuild(): initing (%lu) failed, " - "aborting rebuild\n", hotspare->svc_id); + "aborting rebuild\n", rebuild_ext->svc_id); goto end; } + HR_DEBUG("hr_raid4_rebuild(): starting rebuild on (%lu)\n", + rebuild_ext->svc_id); + + hr_update_ext_status(vol, bad, HR_EXT_REBUILD); + hr_update_vol_status(vol, HR_VOL_REBUILD); + uint64_t max_blks = DATA_XFER_LIMIT / vol->bsize; uint64_t left = vol->data_blkno / (vol->extent_no - 1); buf = malloc(max_blks * vol->bsize); @@ -704,6 +705,7 @@ static errno_t hr_raid4_rebuild(void *arg) uint64_t ba = 0, cnt; hr_add_ba_offset(vol, &ba); + while (left != 0) { cnt = min(left, max_blks); @@ -734,7 +736,7 @@ static errno_t hr_raid4_rebuild(void *arg) first = false; } - rc = block_write_direct(hotspare->svc_id, ba, cnt, xorbuf); + rc = block_write_direct(rebuild_ext->svc_id, ba, cnt, xorbuf); if (rc != EOK) { hr_raid4_handle_extent_error(vol, bad, rc); HR_ERROR("rebuild on \"%s\" (%lu), failed due to " diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index fb0fdb421b..f671ebbb52 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -157,7 +157,8 @@ errno_t hr_raid5_add_hotspare(hr_volume_t *vol, service_id_t hotspare) } vol->hotspares[vol->hotspare_no].svc_id = hotspare; - vol->hotspares[vol->hotspare_no].status = HR_EXT_HOTSPARE; + hr_update_hotspare_status(vol, vol->hotspare_no, HR_EXT_HOTSPARE); + vol->hotspare_no++; /* @@ -168,7 +169,7 @@ errno_t hr_raid5_add_hotspare(hr_volume_t *vol, service_id_t hotspare) "spawning new rebuild fibril\n"); fid_t fib = fibril_create(hr_raid5_rebuild, vol); if (fib == 0) - return EINVAL; + return ENOMEM; fibril_start(fib); fibril_detach(fib); } @@ -229,7 +230,7 @@ static errno_t hr_raid5_vol_usable(hr_volume_t *vol) vol->status == HR_VOL_DEGRADED || vol->status == HR_VOL_REBUILD) return EOK; - return EINVAL; + return EIO; } /* @@ -254,39 +255,29 @@ static errno_t hr_raid5_update_vol_status(hr_volume_t *vol) switch (bad) { case 0: - if (old_state != HR_VOL_ONLINE) { - HR_WARN("RAID 5 has all extents online, " - "marking \"%s\" (%lu) as ONLINE", - vol->devname, vol->svc_id); - vol->status = HR_VOL_ONLINE; - } + if (old_state != HR_VOL_ONLINE) + hr_update_vol_status(vol, HR_VOL_ONLINE); return EOK; case 1: if (old_state != HR_VOL_DEGRADED && old_state != HR_VOL_REBUILD) { - HR_WARN("RAID 5 array \"%s\" (%lu) has 1 extent " - "inactive, marking as DEGRADED", - vol->devname, vol->svc_id); - vol->status = HR_VOL_DEGRADED; + + hr_update_vol_status(vol, HR_VOL_DEGRADED); + if (vol->hotspare_no > 0) { fid_t fib = fibril_create(hr_raid5_rebuild, vol); - if (fib == 0) { - return EINVAL; - } + if (fib == 0) + return ENOMEM; fibril_start(fib); fibril_detach(fib); } } return EOK; default: - if (old_state != HR_VOL_FAULTY) { - HR_WARN("RAID 5 array \"%s\" (%lu) has more " - "than one 1 extent inactive, marking as FAULTY", - vol->devname, vol->svc_id); - vol->status = HR_VOL_FAULTY; - } - return EINVAL; + if (old_state != HR_VOL_FAULTY) + hr_update_vol_status(vol, HR_VOL_FAULTY); + return EIO; } } @@ -559,6 +550,7 @@ static errno_t hr_raid5_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, } left = cnt; + while (left != 0) { phys_block = ext_stripe * strip_size + strip_off; cnt = min(left, strip_size - strip_off); @@ -673,34 +665,43 @@ static errno_t hr_raid5_rebuild(void *arg) goto end; } - block_fini(vol->extents[bad].svc_id); - size_t hotspare_idx = vol->hotspare_no - 1; + hr_ext_status_t hs_state = vol->hotspares[hotspare_idx].status; + if (hs_state != HR_EXT_HOTSPARE) { + HR_ERROR("hr_raid5_rebuild(): invalid hotspare state \"%s\", " + "aborting rebuild\n", hr_get_ext_status_msg(hs_state)); + rc = EINVAL; + goto end; + } + + HR_DEBUG("hr_raid5_rebuild(): swapping in hotspare\n"); + + block_fini(vol->extents[bad].svc_id); + vol->extents[bad].svc_id = vol->hotspares[hotspare_idx].svc_id; - hr_update_ext_status(vol, bad, HR_EXT_REBUILD); + hr_update_ext_status(vol, bad, HR_EXT_HOTSPARE); vol->hotspares[hotspare_idx].svc_id = 0; - vol->hotspares[hotspare_idx].status = HR_EXT_MISSING; - vol->hotspare_no--; + hr_update_hotspare_status(vol, hotspare_idx, HR_EXT_MISSING); - HR_WARN("hr_raid5_rebuild(): changing volume \"%s\" (%lu) state " - "from %s to %s\n", vol->devname, vol->svc_id, - hr_get_vol_status_msg(vol->status), - hr_get_vol_status_msg(HR_VOL_REBUILD)); - vol->status = HR_VOL_REBUILD; - - hr_extent_t *hotspare = &vol->extents[bad]; + vol->hotspare_no--; - HR_DEBUG("hr_raid5_rebuild(): initing (%lu)\n", hotspare->svc_id); + hr_extent_t *rebuild_ext = &vol->extents[bad]; - rc = block_init(hotspare->svc_id); + rc = block_init(rebuild_ext->svc_id); if (rc != EOK) { HR_ERROR("hr_raid5_rebuild(): initing (%lu) failed, " - "aborting rebuild\n", hotspare->svc_id); + "aborting rebuild\n", rebuild_ext->svc_id); goto end; } + HR_DEBUG("hr_raid5_rebuild(): starting rebuild on (%lu)\n", + rebuild_ext->svc_id); + + hr_update_ext_status(vol, bad, HR_EXT_REBUILD); + hr_update_vol_status(vol, HR_VOL_REBUILD); + uint64_t max_blks = DATA_XFER_LIMIT / vol->bsize; uint64_t left = vol->data_blkno / (vol->extent_no - 1); buf = malloc(max_blks * vol->bsize); @@ -708,6 +709,7 @@ static errno_t hr_raid5_rebuild(void *arg) uint64_t ba = 0, cnt; hr_add_ba_offset(vol, &ba); + while (left != 0) { cnt = min(left, max_blks); @@ -740,7 +742,7 @@ static errno_t hr_raid5_rebuild(void *arg) first = false; } - rc = block_write_direct(hotspare->svc_id, ba, cnt, xorbuf); + rc = block_write_direct(rebuild_ext->svc_id, ba, cnt, xorbuf); if (rc != EOK) { hr_raid5_handle_extent_error(vol, bad, rc); HR_ERROR("rebuild on \"%s\" (%lu), failed due to " diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 1a01d90d6d..f1a6fa31e7 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -203,13 +203,31 @@ void hr_add_ba_offset(hr_volume_t *vol, uint64_t *ba) *ba = *ba + vol->data_offset; } -void hr_update_ext_status(hr_volume_t *vol, uint64_t extent, hr_ext_status_t s) +void hr_update_ext_status(hr_volume_t *vol, size_t extent, hr_ext_status_t s) { - HR_WARN("vol %s, changing extent: %lu, to status: %s", - vol->devname, extent, hr_get_ext_status_msg(s)); + hr_ext_status_t old = vol->extents[extent].status; + HR_WARN("\"%s\": changing state of extent %lu: %s -> %s\n", + vol->devname, extent, hr_get_ext_status_msg(old), + hr_get_ext_status_msg(s)); vol->extents[extent].status = s; } +void hr_update_hotspare_status(hr_volume_t *vol, size_t hs, hr_ext_status_t s) +{ + hr_ext_status_t old = vol->hotspares[hs].status; + HR_WARN("\"%s\": changing state of hotspare %lu: %s -> %s\n", + vol->devname, hs, hr_get_ext_status_msg(old), + hr_get_ext_status_msg(s)); + vol->hotspares[hs].status = s; +} + +void hr_update_vol_status(hr_volume_t *vol, hr_vol_status_t s) +{ + HR_WARN("\"%s\": changing state: %s -> %s\n", vol->devname, + hr_get_vol_status_msg(vol->status), hr_get_vol_status_msg(s)); + vol->status = s; +} + /* * Do a whole sync (ba = 0, cnt = 0) across all extents, * and update extent status. *For now*, the caller has to diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index 502b82f87c..b4613574ae 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -55,7 +55,9 @@ extern errno_t hr_register_volume(hr_volume_t *); extern errno_t hr_check_devs(hr_volume_t *, uint64_t *, size_t *); extern errno_t hr_check_ba_range(hr_volume_t *, size_t, uint64_t); extern void hr_add_ba_offset(hr_volume_t *, uint64_t *); -extern void hr_update_ext_status(hr_volume_t *, uint64_t, hr_ext_status_t); +extern void hr_update_ext_status(hr_volume_t *, size_t, hr_ext_status_t); +extern void hr_update_hotspare_status(hr_volume_t *, size_t, hr_ext_status_t); +extern void hr_update_vol_status(hr_volume_t *, hr_vol_status_t); extern void hr_sync_all_extents(hr_volume_t *); extern size_t hr_count_extents(hr_volume_t *, hr_ext_status_t); From 586b39d8d7511fc0d699b0599563a28895d58573 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Thu, 28 Nov 2024 18:12:36 +0100 Subject: [PATCH 086/324] hrctl: handle unkown options --- uspace/app/hrctl/hrctl.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index 656981131f..6260ae9d02 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -253,10 +253,6 @@ int main(int argc, char **argv) c = getopt_long(argc, argv, "hsC:c:A:a:l:0145Ln:D:F:H:", long_options, NULL); switch (c) { - case 'h': - usage(); - free(cfg); - return 0; case 's': free(cfg); rc = hr_print_status(); @@ -379,6 +375,11 @@ int main(int argc, char **argv) return 1; else return 0; + case 'h': + default: + usage(); + free(cfg); + return 0; } } From d7768d1115f533b237625835d8aed661b5451cca Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 6 Dec 2024 20:46:43 +0100 Subject: [PATCH 087/324] hr: add different RAID4,5 layouts Also prepare the metadata for metada versioning and sync counter. --- uspace/srv/bd/hr/hr.c | 3 ++ uspace/srv/bd/hr/raid5.c | 77 ++++++++++++++++++++++++++++------- uspace/srv/bd/hr/superblock.c | 17 +++++--- uspace/srv/bd/hr/superblock.h | 16 ++++++-- uspace/srv/bd/hr/var.h | 16 +++++++- 5 files changed, 104 insertions(+), 25 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 4198cc549d..232c5b53be 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -187,12 +187,14 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) switch (new_volume->level) { case HR_LVL_1: + new_volume->RLQ = 0x00; /* XXX: yet unused */ new_volume->hr_ops.create = hr_raid1_create; new_volume->hr_ops.init = hr_raid1_init; new_volume->hr_ops.status_event = hr_raid1_status_event; new_volume->hr_ops.add_hotspare = hr_raid1_add_hotspare; break; case HR_LVL_0: + new_volume->RLQ = 0x00; new_volume->hr_ops.create = hr_raid0_create; new_volume->hr_ops.init = hr_raid0_init; new_volume->hr_ops.status_event = hr_raid0_status_event; @@ -204,6 +206,7 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) new_volume->hr_ops.add_hotspare = hr_raid4_add_hotspare; break; case HR_LVL_5: + new_volume->RLQ = HR_RLQ_RAID5_NR; new_volume->hr_ops.create = hr_raid5_create; new_volume->hr_ops.init = hr_raid5_init; new_volume->hr_ops.status_event = hr_raid5_status_event; diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index f671ebbb52..f02bf69229 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -94,7 +94,7 @@ errno_t hr_raid5_create(hr_volume_t *new_volume) { errno_t rc; - assert(new_volume->level == HR_LVL_5); + assert(new_volume->level == HR_LVL_5 || new_volume->level == HR_LVL_4); if (new_volume->extent_no < 3) { HR_ERROR("RAID 5 array needs at least 3 devices\n"); @@ -120,7 +120,7 @@ errno_t hr_raid5_init(hr_volume_t *vol) size_t bsize; uint64_t total_blkno; - assert(vol->level == HR_LVL_5); + assert(vol->level == HR_LVL_5 || vol->level == HR_LVL_4); rc = hr_check_devs(vol, &total_blkno, &bsize); if (rc != EOK) @@ -530,14 +530,45 @@ static errno_t hr_raid5_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, if (rc != EOK) return rc; + uint8_t RLQ = vol->RLQ; + hr_level_t level = vol->level; + uint64_t strip_size = vol->strip_size / vol->bsize; /* in blocks */ uint64_t stripe = (ba / strip_size); /* stripe number */ - uint64_t p_extent = (stripe / (vol->extent_no - 1)) % vol->extent_no; /* parity extent */ + + /* parity extent */ + uint64_t p_extent; + if (level == HR_LVL_4 && RLQ == HR_RLQ_RAID4_0) { + p_extent = 0; + } else if (level == HR_LVL_4 && RLQ == HR_RLQ_RAID4_N) { + p_extent = vol->extent_no - 1; + } else if (level == HR_LVL_5 && RLQ == HR_RLQ_RAID5_0R) { + p_extent = (stripe / (vol->extent_no - 1)) % vol->extent_no; + } else if (level == HR_LVL_5 && + (RLQ == HR_RLQ_RAID5_NR || RLQ == HR_RLQ_RAID5_NC)) { + p_extent = (vol->extent_no - 1) - + (stripe / (vol->extent_no - 1)) % vol->extent_no; + } else { + return EINVAL; + } + uint64_t extent; - if ((stripe % (vol->extent_no - 1)) < p_extent) - extent = (stripe % (vol->extent_no - 1)); - else - extent = ((stripe % (vol->extent_no - 1)) + 1); + if (level == HR_LVL_4 && RLQ == HR_RLQ_RAID4_0) { + extent = (stripe % (vol->extent_no - 1)) + 1; + } else if (level == HR_LVL_4 && RLQ == HR_RLQ_RAID4_N) { + extent = stripe % (vol->extent_no - 1); + } else if (level == HR_LVL_5 && + (RLQ == HR_RLQ_RAID5_0R || RLQ == HR_RLQ_RAID5_NR)) { + if ((stripe % (vol->extent_no - 1)) < p_extent) + extent = stripe % (vol->extent_no - 1); + else + extent = (stripe % (vol->extent_no - 1)) + 1; + } else if (level == HR_LVL_5 && RLQ == HR_RLQ_RAID5_NC) { + extent = ((stripe % (vol->extent_no - 1)) + p_extent + 1) % vol->extent_no; + } else { + return EINVAL; + } + uint64_t ext_stripe = stripe / (vol->extent_no - 1); /* stripe level */ uint64_t strip_off = ba % strip_size; /* strip offset */ @@ -616,15 +647,31 @@ static errno_t hr_raid5_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, left -= cnt; strip_off = 0; - if (extent + 1 >= vol->extent_no || - (extent + 1 == p_extent && p_extent + 1 >= vol->extent_no)) - ext_stripe++; stripe++; - p_extent = (stripe / (vol->extent_no - 1)) % vol->extent_no; /* parity extent */ - if ((stripe % (vol->extent_no - 1)) < p_extent) - extent = (stripe % (vol->extent_no - 1)); - else - extent = ((stripe % (vol->extent_no - 1)) + 1); + + ext_stripe = stripe / (vol->extent_no - 1); /* stripe level */ + + if (level == HR_LVL_5 && RLQ == HR_RLQ_RAID5_0R) { + p_extent = (stripe / (vol->extent_no - 1)) % vol->extent_no; + } else if (level == HR_LVL_5 && + (RLQ == HR_RLQ_RAID5_NR || RLQ == HR_RLQ_RAID5_NC)) { + p_extent = (vol->extent_no - 1) - + (stripe / (vol->extent_no - 1)) % vol->extent_no; + } + + if (level == HR_LVL_4 && RLQ == HR_RLQ_RAID4_0) { + extent = (stripe % (vol->extent_no - 1)) + 1; + } else if (level == HR_LVL_4 && RLQ == HR_RLQ_RAID4_N) { + extent = stripe % (vol->extent_no - 1); + } else if (level == HR_LVL_5 && + (RLQ == HR_RLQ_RAID5_0R || RLQ == HR_RLQ_RAID5_NR)) { + if ((stripe % (vol->extent_no - 1)) < p_extent) + extent = stripe % (vol->extent_no - 1); + else + extent = (stripe % (vol->extent_no - 1)) + 1; + } else if (level == HR_LVL_5 && RLQ == HR_RLQ_RAID5_NC) { + extent = ((stripe % (vol->extent_no - 1)) + p_extent + 1) % vol->extent_no; + } } error: diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index 61ccd83433..846dc331c9 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -152,13 +152,17 @@ static errno_t hr_fill_meta_from_vol(hr_volume_t *vol, hr_metadata_t *metadata) } metadata->magic = host2uint64_t_le(HR_MAGIC); + metadata->version = host2uint32_t_le(~(0U)); /* unused */ metadata->extent_no = host2uint32_t_le(vol->extent_no); + /* index filled separately for each extent */ metadata->level = host2uint32_t_le(vol->level); + metadata->layout = host2uint32_t_le(vol->RLQ); + metadata->strip_size = host2uint32_t_le(vol->strip_size); metadata->nblocks = host2uint64_t_le(vol->nblocks); metadata->data_blkno = host2uint64_t_le(vol->data_blkno); - metadata->data_offset = host2uint32_t_le(vol->data_offset); - metadata->strip_size = host2uint32_t_le(vol->strip_size); - + metadata->data_offset = host2uint64_t_le(vol->data_offset); + metadata->counter = host2uint64_t_le(~(0UL)); /* unused */ + /* UUID generated separately for each extent */ str_cpy(metadata->devname, HR_DEVNAME_LEN, vol->devname); return EOK; @@ -230,11 +234,14 @@ errno_t hr_fill_vol_from_meta(hr_volume_t *vol) goto end; } + /* TODO: handle version */ vol->level = uint32_t_le2host(metadata->level); + vol->RLQ = (uint8_t)uint32_t_le2host(metadata->layout); + vol->strip_size = uint32_t_le2host(metadata->strip_size); vol->nblocks = uint64_t_le2host(metadata->nblocks); vol->data_blkno = uint64_t_le2host(metadata->data_blkno); - vol->data_offset = uint32_t_le2host(metadata->data_offset); - vol->strip_size = uint32_t_le2host(metadata->strip_size); + vol->data_offset = uint64_t_le2host(metadata->data_offset); + vol->counter = uint64_t_le2host(0x00); /* unused */ if (str_cmp(metadata->devname, vol->devname) != 0) { HR_WARN("devname on metadata (%s) and config (%s) differ, " diff --git a/uspace/srv/bd/hr/superblock.h b/uspace/srv/bd/hr/superblock.h index 73504f43de..7bce621dca 100644 --- a/uspace/srv/bd/hr/superblock.h +++ b/uspace/srv/bd/hr/superblock.h @@ -47,15 +47,23 @@ typedef struct hr_metadata { uint64_t magic; + uint32_t version; /* unused XXX */ uint32_t extent_no; + + uint32_t index; /* index of disk in array */ uint32_t level; + uint32_t layout; + uint32_t strip_size; + uint64_t nblocks; /* all blocks */ uint64_t data_blkno; /* usable blocks */ - uint32_t data_offset; /* block where data starts */ - uint32_t index; /* index of disk in array */ - uint32_t strip_size; - uint32_t status; /* yet unused */ + + uint64_t data_offset; /* block where data starts */ + + uint64_t counter; /* unused */ + uint8_t uuid[HR_UUID_LEN]; + char devname[HR_DEVNAME_LEN]; } hr_metadata_t; diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index 9bd3afe6a2..a1c603b814 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -69,14 +69,28 @@ typedef struct hr_volume { size_t bsize; uint64_t nblocks; uint64_t data_blkno; - uint32_t data_offset; /* in blocks */ + uint64_t data_offset; /* in blocks */ uint32_t strip_size; uint64_t rebuild_blk; + uint64_t counter; /* metadata syncing */ + service_id_t svc_id; hr_vol_status_t status; hr_level_t level; + /* + * SNIA + * Common RAID Disk Data Format + * Specification + * Version 2.0 Revision 19 + */ +#define HR_RLQ_RAID4_0 0x00 /* RAID-4 Non-Rotating Parity 0 */ +#define HR_RLQ_RAID4_N 0x01 /* RAID-4 Non-Rotating Parity N */ +#define HR_RLQ_RAID5_0R 0x00 /* RAID-5 Rotating Parity 0 with Data Restart */ +#define HR_RLQ_RAID5_NR 0x02 /* RAID-5 Rotating Parity N with Data Restart */ +#define HR_RLQ_RAID5_NC 0x03 /* RAID-5 Rotating Parity N with Data Continuation */ + uint8_t RLQ; /* RAID Level Qualifier */ char devname[HR_DEVNAME_LEN]; } hr_volume_t; From 241c3f65ad390b16501fdfa8f7e6f3fe3cb9fac9 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 6 Dec 2024 20:55:45 +0100 Subject: [PATCH 088/324] hr: move RAID4 to RAID5 Removes whole raid4.c, as RAID4 is implemented via RLQs in RAID5. --- uspace/srv/bd/hr/hr.c | 9 +- uspace/srv/bd/hr/meson.build | 2 +- uspace/srv/bd/hr/raid4.c | 783 ----------------------------------- 3 files changed, 6 insertions(+), 788 deletions(-) delete mode 100644 uspace/srv/bd/hr/raid4.c diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 232c5b53be..634d57b696 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -200,10 +200,11 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) new_volume->hr_ops.status_event = hr_raid0_status_event; break; case HR_LVL_4: - new_volume->hr_ops.create = hr_raid4_create; - new_volume->hr_ops.init = hr_raid4_init; - new_volume->hr_ops.status_event = hr_raid4_status_event; - new_volume->hr_ops.add_hotspare = hr_raid4_add_hotspare; + new_volume->RLQ = HR_RLQ_RAID4_N; + new_volume->hr_ops.create = hr_raid5_create; + new_volume->hr_ops.init = hr_raid5_init; + new_volume->hr_ops.status_event = hr_raid5_status_event; + new_volume->hr_ops.add_hotspare = hr_raid5_add_hotspare; break; case HR_LVL_5: new_volume->RLQ = HR_RLQ_RAID5_NR; diff --git a/uspace/srv/bd/hr/meson.build b/uspace/srv/bd/hr/meson.build index 2d61303f70..5ff018c497 100644 --- a/uspace/srv/bd/hr/meson.build +++ b/uspace/srv/bd/hr/meson.build @@ -27,4 +27,4 @@ # deps = [ 'block', 'device' ] -src = files('hr.c', 'raid0.c', 'raid1.c', 'raid4.c', 'raid5.c', 'superblock.c', 'util.c') +src = files('hr.c', 'raid0.c', 'raid1.c', 'raid5.c', 'superblock.c', 'util.c') diff --git a/uspace/srv/bd/hr/raid4.c b/uspace/srv/bd/hr/raid4.c deleted file mode 100644 index 8aee9bd27d..0000000000 --- a/uspace/srv/bd/hr/raid4.c +++ /dev/null @@ -1,783 +0,0 @@ -/* - * Copyright (c) 2024 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 -#include -#include -#include -#include -#include - -#include "superblock.h" -#include "util.h" -#include "var.h" - -extern loc_srv_t *hr_srv; - -static errno_t hr_raid4_vol_usable(hr_volume_t *); -static ssize_t hr_raid4_get_bad_ext(hr_volume_t *); -static errno_t hr_raid4_update_vol_status(hr_volume_t *); -static void hr_raid4_handle_extent_error(hr_volume_t *, size_t, errno_t); -static void xor(void *, const void *, size_t); -static errno_t hr_raid4_read_degraded(hr_volume_t *, uint64_t, uint64_t, - void *, size_t); -static errno_t hr_raid4_write(hr_volume_t *, uint64_t, aoff64_t, const void *, - size_t); -static errno_t hr_raid4_write_parity(hr_volume_t *, uint64_t, uint64_t, - const void *, size_t); -static errno_t hr_raid4_bd_op(hr_bd_op_type_t, bd_srv_t *, aoff64_t, size_t, - void *, const void *, size_t); -static errno_t hr_raid4_rebuild(void *); - -/* bdops */ -static errno_t hr_raid4_bd_open(bd_srvs_t *, bd_srv_t *); -static errno_t hr_raid4_bd_close(bd_srv_t *); -static errno_t hr_raid4_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, - size_t); -static errno_t hr_raid4_bd_sync_cache(bd_srv_t *, aoff64_t, size_t); -static errno_t hr_raid4_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, - const void *, size_t); -static errno_t hr_raid4_bd_get_block_size(bd_srv_t *, size_t *); -static errno_t hr_raid4_bd_get_num_blocks(bd_srv_t *, aoff64_t *); - -static errno_t hr_raid4_write_parity(hr_volume_t *, uint64_t, uint64_t, - const void *, size_t); - -static bd_ops_t hr_raid4_bd_ops = { - .open = hr_raid4_bd_open, - .close = hr_raid4_bd_close, - .sync_cache = hr_raid4_bd_sync_cache, - .read_blocks = hr_raid4_bd_read_blocks, - .write_blocks = hr_raid4_bd_write_blocks, - .get_block_size = hr_raid4_bd_get_block_size, - .get_num_blocks = hr_raid4_bd_get_num_blocks -}; - -errno_t hr_raid4_create(hr_volume_t *new_volume) -{ - errno_t rc; - - assert(new_volume->level == HR_LVL_4); - - if (new_volume->extent_no < 3) { - HR_ERROR("RAID 4 array needs at least 3 devices\n"); - return EINVAL; - } - - rc = hr_raid4_update_vol_status(new_volume); - if (rc != EOK) - return rc; - - bd_srvs_init(&new_volume->hr_bds); - new_volume->hr_bds.ops = &hr_raid4_bd_ops; - new_volume->hr_bds.sarg = new_volume; - - rc = hr_register_volume(new_volume); - - return rc; -} - -errno_t hr_raid4_init(hr_volume_t *vol) -{ - errno_t rc; - size_t bsize; - uint64_t total_blkno; - - assert(vol->level == HR_LVL_4); - - rc = hr_check_devs(vol, &total_blkno, &bsize); - if (rc != EOK) - return rc; - - vol->nblocks = total_blkno; - vol->bsize = bsize; - vol->data_offset = HR_DATA_OFF; - vol->data_blkno = vol->nblocks - (vol->data_offset * vol->extent_no) - - (vol->nblocks / vol->extent_no); - vol->strip_size = HR_STRIP_SIZE; - - return EOK; -} - -void hr_raid4_status_event(hr_volume_t *vol) -{ - fibril_mutex_lock(&vol->lock); - (void)hr_raid4_update_vol_status(vol); - fibril_mutex_unlock(&vol->lock); -} - -errno_t hr_raid4_add_hotspare(hr_volume_t *vol, service_id_t hotspare) -{ - HR_DEBUG("hr_raid4_add_hotspare()\n"); - - fibril_mutex_lock(&vol->lock); - - if (vol->hotspare_no >= HR_MAX_HOTSPARES) { - HR_ERROR("hr_raid4_add_hotspare(): cannot add more hotspares " - "to \"%s\"\n", vol->devname); - fibril_mutex_unlock(&vol->lock); - return ELIMIT; - } - - vol->hotspares[vol->hotspare_no].svc_id = hotspare; - hr_update_hotspare_status(vol, vol->hotspare_no, HR_EXT_HOTSPARE); - - vol->hotspare_no++; - - /* - * If the volume is degraded, start rebuild right away. - */ - if (vol->status == HR_VOL_DEGRADED) { - HR_DEBUG("hr_raid4_add_hotspare(): volume in DEGRADED state, " - "spawning new rebuild fibril\n"); - fid_t fib = fibril_create(hr_raid4_rebuild, vol); - if (fib == 0) - return ENOMEM; - fibril_start(fib); - fibril_detach(fib); - } - - fibril_mutex_unlock(&vol->lock); - - return EOK; -} - -static errno_t hr_raid4_bd_open(bd_srvs_t *bds, bd_srv_t *bd) -{ - HR_DEBUG("hr_bd_open()\n"); - return EOK; -} - -static errno_t hr_raid4_bd_close(bd_srv_t *bd) -{ - HR_DEBUG("hr_bd_close()\n"); - return EOK; -} - -static errno_t hr_raid4_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) -{ - return hr_raid4_bd_op(HR_BD_SYNC, bd, ba, cnt, NULL, NULL, 0); -} - -static errno_t hr_raid4_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, - void *buf, size_t size) -{ - return hr_raid4_bd_op(HR_BD_READ, bd, ba, cnt, buf, NULL, size); -} - -static errno_t hr_raid4_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, - const void *data, size_t size) -{ - return hr_raid4_bd_op(HR_BD_WRITE, bd, ba, cnt, NULL, data, size); -} - -static errno_t hr_raid4_bd_get_block_size(bd_srv_t *bd, size_t *rsize) -{ - hr_volume_t *vol = bd->srvs->sarg; - - *rsize = vol->bsize; - return EOK; -} - -static errno_t hr_raid4_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb) -{ - hr_volume_t *vol = bd->srvs->sarg; - - *rnb = vol->data_blkno; - return EOK; -} - -static errno_t hr_raid4_vol_usable(hr_volume_t *vol) -{ - if (vol->status == HR_VOL_ONLINE || - vol->status == HR_VOL_DEGRADED || - vol->status == HR_VOL_REBUILD) - return EOK; - return EIO; -} - -/* - * Returns (-1) if all extents are online, - * else returns index of first bad one. - */ -static ssize_t hr_raid4_get_bad_ext(hr_volume_t *vol) -{ - for (size_t i = 0; i < vol->extent_no; i++) - if (vol->extents[i].status != HR_EXT_ONLINE) - return i; - return -1; -} - -static errno_t hr_raid4_update_vol_status(hr_volume_t *vol) -{ - hr_vol_status_t old_state = vol->status; - size_t bad = 0; - for (size_t i = 0; i < vol->extent_no; i++) - if (vol->extents[i].status != HR_EXT_ONLINE) - bad++; - - switch (bad) { - case 0: - if (old_state != HR_VOL_ONLINE) - hr_update_vol_status(vol, HR_VOL_ONLINE); - return EOK; - case 1: - if (old_state != HR_VOL_DEGRADED && - old_state != HR_VOL_REBUILD) { - - hr_update_vol_status(vol, HR_VOL_DEGRADED); - - if (vol->hotspare_no > 0) { - fid_t fib = fibril_create(hr_raid4_rebuild, - vol); - if (fib == 0) - return ENOMEM; - fibril_start(fib); - fibril_detach(fib); - } - } - return EOK; - default: - if (old_state != HR_VOL_FAULTY) - hr_update_vol_status(vol, HR_VOL_FAULTY); - return EIO; - } -} - -static void hr_raid4_handle_extent_error(hr_volume_t *vol, size_t extent, - errno_t rc) -{ - if (rc == ENOENT) - hr_update_ext_status(vol, extent, HR_EXT_MISSING); - else if (rc != EOK) - hr_update_ext_status(vol, extent, HR_EXT_FAILED); -} - -static void xor(void *dst, const void *src, size_t size) -{ - size_t i; - uint64_t *d = dst; - const uint64_t *s = src; - - for (i = 0; i < size / sizeof(uint64_t); ++i) - *d++ ^= *s++; -} - -static errno_t hr_raid4_read_degraded(hr_volume_t *vol, uint64_t bad, - uint64_t block, void *data, size_t cnt) -{ - errno_t rc; - size_t i; - void *xorbuf; - void *buf; - uint64_t len = vol->bsize * cnt; - - xorbuf = malloc(len); - if (xorbuf == NULL) - return ENOMEM; - - buf = malloc(len); - if (buf == NULL) { - free(xorbuf); - return ENOMEM; - } - - /* read all other extents in the stripe */ - bool first = true; - for (i = 0; i < vol->extent_no; i++) { - if (i == bad) - continue; - - if (first) { - rc = block_read_direct(vol->extents[i].svc_id, block, - cnt, xorbuf); - if (rc != EOK) - goto end; - - first = false; - } else { - rc = block_read_direct(vol->extents[i].svc_id, block, - cnt, buf); - if (rc != EOK) - goto end; - - xor(xorbuf, buf, len); - } - } - - memcpy(data, xorbuf, len); -end: - free(xorbuf); - free(buf); - return rc; -} - -static errno_t hr_raid4_write(hr_volume_t *vol, uint64_t extent, aoff64_t ba, - const void *data, size_t cnt) -{ - errno_t rc; - size_t i; - void *xorbuf; - void *buf; - uint64_t len = vol->bsize * cnt; - - ssize_t bad = hr_raid4_get_bad_ext(vol); - if (bad < 1) { - rc = block_write_direct(vol->extents[extent].svc_id, ba, cnt, - data); - if (rc != EOK) - return rc; - /* - * DEGRADED parity - skip parity write - */ - if (bad == 0) - return EOK; - - rc = hr_raid4_write_parity(vol, extent, ba, data, cnt); - return rc; - } - - xorbuf = malloc(len); - if (xorbuf == NULL) - return ENOMEM; - - buf = malloc(len); - if (buf == NULL) { - free(xorbuf); - return ENOMEM; - } - - if (extent == (size_t)bad) { - /* - * new parity = read other and xor in new data - * - * write new parity - */ - bool first = true; - for (i = 1; i < vol->extent_no; i++) { - if (i == (size_t)bad) - continue; - - if (first) { - rc = block_read_direct(vol->extents[i].svc_id, - ba, cnt, xorbuf); - if (rc != EOK) - goto end; - - first = false; - } else { - rc = block_read_direct(vol->extents[i].svc_id, - ba, cnt, buf); - if (rc != EOK) - goto end; - - xor(xorbuf, buf, len); - } - } - xor(xorbuf, data, len); - rc = block_write_direct(vol->extents[0].svc_id, ba, cnt, - xorbuf); - if (rc != EOK) - goto end; - } else { - /* - * new parity = xor original data and old parity and new data - * - * write parity, new data - */ - rc = block_read_direct(vol->extents[extent].svc_id, ba, cnt, - xorbuf); - if (rc != EOK) - goto end; - rc = block_read_direct(vol->extents[0].svc_id, ba, cnt, buf); - if (rc != EOK) - goto end; - - xor(xorbuf, buf, len); - - xor(xorbuf, data, len); - - rc = block_write_direct(vol->extents[0].svc_id, ba, cnt, - xorbuf); - if (rc != EOK) - goto end; - rc = block_write_direct(vol->extents[extent].svc_id, ba, cnt, - data); - if (rc != EOK) - goto end; - } -end: - free(xorbuf); - free(buf); - return rc; -} - -static errno_t hr_raid4_write_parity(hr_volume_t *vol, uint64_t extent, - uint64_t block, const void *data, size_t cnt) -{ - errno_t rc; - size_t i; - void *xorbuf; - void *buf; - uint64_t len = vol->bsize * cnt; - - xorbuf = malloc(len); - if (xorbuf == NULL) - return ENOMEM; - - buf = malloc(len); - if (buf == NULL) { - free(xorbuf); - return ENOMEM; - } - - /* - * parity = read and xor all other data extents, xor in new data - * - * XXX: subtract method - */ - bool first = true; - for (i = 1; i < vol->extent_no; i++) { - if (first) { - if (i == extent) { - memcpy(xorbuf, data, len); - } else { - rc = block_read_direct(vol->extents[i].svc_id, - block, cnt, xorbuf); - if (rc != EOK) - goto end; - } - - first = false; - } else { - if (i == extent) { - xor(xorbuf, data, len); - } else { - rc = block_read_direct(vol->extents[i].svc_id, - block, cnt, buf); - if (rc != EOK) - goto end; - - xor(xorbuf, buf, len); - } - } - } - - rc = block_write_direct(vol->extents[0].svc_id, block, cnt, xorbuf); -end: - free(xorbuf); - free(buf); - return rc; -} - -static errno_t hr_raid4_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, - size_t cnt, void *dst, const void *src, size_t size) -{ - hr_volume_t *vol = bd->srvs->sarg; - errno_t rc; - uint64_t phys_block, len; - size_t left; - const uint8_t *data_write = src; - uint8_t *data_read = dst; - - /* propagate sync */ - if (type == HR_BD_SYNC && ba == 0 && cnt == 0) { - hr_sync_all_extents(vol); - rc = hr_raid4_update_vol_status(vol); - return rc; - } - - if (type == HR_BD_READ || type == HR_BD_WRITE) - if (size < cnt * vol->bsize) - return EINVAL; - - rc = hr_check_ba_range(vol, cnt, ba); - if (rc != EOK) - return rc; - - uint64_t strip_size = vol->strip_size / vol->bsize; /* in blocks */ - uint64_t stripe = (ba / strip_size); /* stripe number */ - uint64_t extent = (stripe % (vol->extent_no - 1)) + 1; - uint64_t ext_stripe = stripe / (vol->extent_no - 1); /* stripe level */ - uint64_t strip_off = ba % strip_size; /* strip offset */ - - fibril_mutex_lock(&vol->lock); - - rc = hr_raid4_vol_usable(vol); - if (rc != EOK) { - fibril_mutex_unlock(&vol->lock); - return EIO; - } - - left = cnt; - - while (left != 0) { - phys_block = ext_stripe * strip_size + strip_off; - cnt = min(left, strip_size - strip_off); - len = vol->bsize * cnt; - hr_add_ba_offset(vol, &phys_block); - switch (type) { - case HR_BD_SYNC: - if (vol->extents[extent].status != HR_EXT_ONLINE) - break; - rc = block_sync_cache(vol->extents[extent].svc_id, - phys_block, cnt); - /* allow unsupported sync */ - if (rc == ENOTSUP) - rc = EOK; - break; - case HR_BD_READ: - retry_read: - ssize_t bad = hr_raid4_get_bad_ext(vol); - if (bad > 0 && extent == (size_t)bad) { - rc = hr_raid4_read_degraded(vol, bad, - phys_block, data_read, cnt); - } else { - rc = block_read_direct(vol->extents[extent].svc_id, - phys_block, cnt, data_read); - } - data_read += len; - break; - case HR_BD_WRITE: - retry_write: - rc = hr_raid4_write(vol, extent, phys_block, - data_write, cnt); - data_write += len; - break; - default: - rc = EINVAL; - goto error; - } - - if (rc == ENOMEM) - goto error; - - hr_raid4_handle_extent_error(vol, extent, rc); - - if (rc != EOK) { - rc = hr_raid4_update_vol_status(vol); - if (rc == EOK) { - /* - * State changed from ONLINE -> DEGRADED, - * rewind and retry - */ - if (type == HR_BD_WRITE) { - data_write -= len; - goto retry_write; - } else if (type == HR_BD_WRITE) { - data_read -= len; - goto retry_read; - } - } else { - rc = EIO; - goto error; - } - } - - left -= cnt; - strip_off = 0; - extent++; - if (extent >= vol->extent_no) { - ext_stripe++; - extent = 1; - } - } - -error: - (void)hr_raid4_update_vol_status(vol); - fibril_mutex_unlock(&vol->lock); - return rc; -} - -static errno_t hr_raid4_rebuild(void *arg) -{ - HR_DEBUG("hr_raid4_rebuild()\n"); - - hr_volume_t *vol = arg; - errno_t rc = EOK; - void *buf = NULL, *xorbuf = NULL; - - fibril_mutex_lock(&vol->lock); - - if (vol->hotspare_no == 0) { - HR_WARN("hr_raid4_rebuild(): no free hotspares on \"%s\", " - "aborting rebuild\n", vol->devname); - /* retval isn't checked for now */ - goto end; - } - - size_t bad = vol->extent_no; - for (size_t i = 0; i < vol->extent_no; i++) { - if (vol->extents[i].status == HR_EXT_FAILED) { - bad = i; - break; - } - } - - if (bad == vol->extent_no) { - HR_WARN("hr_raid4_rebuild(): no bad extent on \"%s\", " - "aborting rebuild\n", vol->devname); - /* retval isn't checked for now */ - goto end; - } - - size_t hotspare_idx = vol->hotspare_no - 1; - - hr_ext_status_t hs_state = vol->hotspares[hotspare_idx].status; - if (hs_state != HR_EXT_HOTSPARE) { - HR_ERROR("hr_raid4_rebuild(): invalid hotspare state \"%s\", " - "aborting rebuild\n", hr_get_ext_status_msg(hs_state)); - rc = EINVAL; - goto end; - } - - HR_DEBUG("hr_raid4_rebuild(): swapping in hotspare\n"); - - block_fini(vol->extents[bad].svc_id); - - vol->extents[bad].svc_id = vol->hotspares[hotspare_idx].svc_id; - hr_update_ext_status(vol, bad, HR_EXT_HOTSPARE); - - vol->hotspares[hotspare_idx].svc_id = 0; - hr_update_hotspare_status(vol, hotspare_idx, HR_EXT_MISSING); - - vol->hotspare_no--; - - hr_extent_t *rebuild_ext = &vol->extents[bad]; - - rc = block_init(rebuild_ext->svc_id); - if (rc != EOK) { - HR_ERROR("hr_raid4_rebuild(): initing (%lu) failed, " - "aborting rebuild\n", rebuild_ext->svc_id); - goto end; - } - - HR_DEBUG("hr_raid4_rebuild(): starting rebuild on (%lu)\n", - rebuild_ext->svc_id); - - hr_update_ext_status(vol, bad, HR_EXT_REBUILD); - hr_update_vol_status(vol, HR_VOL_REBUILD); - - uint64_t max_blks = DATA_XFER_LIMIT / vol->bsize; - uint64_t left = vol->data_blkno / (vol->extent_no - 1); - buf = malloc(max_blks * vol->bsize); - xorbuf = malloc(max_blks * vol->bsize); - - uint64_t ba = 0, cnt; - hr_add_ba_offset(vol, &ba); - - while (left != 0) { - cnt = min(left, max_blks); - - /* - * Almost the same as read_degraded, - * but we don't want to allocate new - * xorbuf each blk rebuild batch. - */ - bool first = true; - for (size_t i = 0; i < vol->extent_no; i++) { - if (i == bad) - continue; - rc = block_read_direct(vol->extents[i].svc_id, ba, cnt, - buf); - if (rc != EOK) { - hr_raid4_handle_extent_error(vol, i, rc); - HR_ERROR("rebuild on \"%s\" (%lu), failed due " - "to a failed ONLINE extent, number %lu\n", - vol->devname, vol->svc_id, i); - goto end; - } - - if (first) - memcpy(xorbuf, buf, cnt * vol->bsize); - else - xor(xorbuf, buf, cnt * vol->bsize); - - first = false; - } - - rc = block_write_direct(rebuild_ext->svc_id, ba, cnt, xorbuf); - if (rc != EOK) { - hr_raid4_handle_extent_error(vol, bad, rc); - HR_ERROR("rebuild on \"%s\" (%lu), failed due to " - "the rebuilt extent number %lu failing\n", - vol->devname, vol->svc_id, bad); - goto end; - } - - ba += cnt; - left -= cnt; - - /* - * Let other IO requests be served - * during rebuild. - */ - fibril_mutex_unlock(&vol->lock); - fibril_mutex_lock(&vol->lock); - } - - HR_DEBUG("hr_raid4_rebuild(): rebuild finished on \"%s\" (%lu), " - "extent number %lu\n", vol->devname, vol->svc_id, hotspare_idx); - - hr_update_ext_status(vol, bad, HR_EXT_ONLINE); - /* - * For now write metadata at the end, because - * we don't sync metada accross extents yet. - */ - hr_write_meta_to_ext(vol, bad); -end: - (void)hr_raid4_update_vol_status(vol); - - fibril_mutex_unlock(&vol->lock); - - if (buf != NULL) - free(buf); - - if (xorbuf != NULL) - free(xorbuf); - - return rc; -} - -/** @} - */ From 4066371f8e1923393b0b2f23b0ae8124945e1d55 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 6 Dec 2024 21:19:21 +0100 Subject: [PATCH 089/324] hr: layout info printing --- uspace/lib/device/include/hr.h | 14 +++++++++++ uspace/lib/device/src/hr.c | 46 ++++++++++++++++++++++++++++++---- uspace/srv/bd/hr/hr.c | 1 + uspace/srv/bd/hr/var.h | 11 -------- 4 files changed, 56 insertions(+), 16 deletions(-) diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index 8443bbf78c..abc0a7b6b5 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -54,6 +54,18 @@ typedef enum hr_level { HR_LVL_UNKNOWN = 0xFF } hr_level_t; +/* + * SNIA + * Common RAID Disk Data Format + * Specification + * Version 2.0 Revision 19 + */ +#define HR_RLQ_RAID4_0 0x00 /* RAID-4 Non-Rotating Parity 0 */ +#define HR_RLQ_RAID4_N 0x01 /* RAID-4 Non-Rotating Parity N */ +#define HR_RLQ_RAID5_0R 0x00 /* RAID-5 Rotating Parity 0 with Data Restart */ +#define HR_RLQ_RAID5_NR 0x02 /* RAID-5 Rotating Parity N with Data Restart */ +#define HR_RLQ_RAID5_NC 0x03 /* RAID-5 Rotating Parity N with Data Continuation */ + typedef enum hr_vol_status { HR_VOL_ONLINE, /* OK, OPTIMAL */ HR_VOL_FAULTY, @@ -96,6 +108,7 @@ typedef struct hr_vol_info { uint32_t strip_size; size_t bsize; hr_vol_status_t status; + uint8_t RLQ; } hr_vol_info_t; extern errno_t hr_sess_init(hr_t **); @@ -108,6 +121,7 @@ extern errno_t hr_print_status(void); extern const char *hr_get_vol_status_msg(hr_vol_status_t); extern const char *hr_get_ext_status_msg(hr_ext_status_t); +extern const char *hr_get_layout_str(hr_level_t, uint8_t); #endif diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index b19bbcdd20..ee9fca6edf 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -132,6 +132,10 @@ static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info) printf("status: %s\n", hr_get_vol_status_msg(vol_info->status)); printf("level: %d\n", vol_info->level); + if (vol_info->level == HR_LVL_4 || vol_info->level == HR_LVL_5) { + printf("layout: %s\n", + hr_get_layout_str(vol_info->level, vol_info->RLQ)); + } if (vol_info->level == HR_LVL_0 || vol_info->level == HR_LVL_4) { if (vol_info->strip_size / 1024 < 1) printf("strip size in bytes: %u\n", @@ -158,12 +162,16 @@ static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info) if (rc != EOK) return rc; } - if (i == 0 && vol_info->level == HR_LVL_4) - printf(" P %s %zu %s\n", hr_get_ext_status_msg(ext->status), i, devname); - else if (vol_info->level == HR_LVL_4) - printf(" %s %zu %s\n", hr_get_ext_status_msg(ext->status), i, devname); - else + if (vol_info->level == HR_LVL_4) { + if ((i == 0 && vol_info->RLQ == HR_RLQ_RAID4_0) || + (i == vol_info->extent_no - 1 && + vol_info->RLQ == HR_RLQ_RAID4_N)) + printf(" P %s %zu %s\n", hr_get_ext_status_msg(ext->status), i, devname); + else + printf(" %s %zu %s\n", hr_get_ext_status_msg(ext->status), i, devname); + } else { printf(" %s %zu %s\n", hr_get_ext_status_msg(ext->status), i, devname); + } } if (vol_info->hotspare_no == 0) @@ -342,5 +350,33 @@ const char *hr_get_ext_status_msg(hr_ext_status_t status) } } +const char *hr_get_layout_str(hr_level_t level, uint8_t RLQ) +{ + switch (level) { + case HR_LVL_4: + switch (RLQ) { + case HR_RLQ_RAID4_0: + return "RAID-4 Non-Rotating Parity 0"; + case HR_RLQ_RAID4_N: + return "RAID-4 Non-Rotating Parity N"; + default: + return "RAID-4 INVALID"; + } + case HR_LVL_5: + switch (RLQ) { + case HR_RLQ_RAID5_0R: + return "RAID-5 Rotating Parity 0 with Data Restart"; + case HR_RLQ_RAID5_NR: + return "RAID-5 Rotating Parity N with Data Restart"; + case HR_RLQ_RAID5_NC: + return "RAID-5 Rotating Parity N with Data Continuation"; + default: + return "RAID-5 INVALID"; + } + default: + return "INVALID"; + } +} + /** @} */ diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 634d57b696..14d381a6b7 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -365,6 +365,7 @@ static void hr_print_status_srv(ipc_call_t *icall) info.strip_size = vol->strip_size; info.bsize = vol->bsize; info.status = vol->status; + info.RLQ = vol->RLQ; if (!async_data_read_receive(&call, &size)) { rc = EREFUSED; diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index a1c603b814..dc83bcea17 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -79,17 +79,6 @@ typedef struct hr_volume { service_id_t svc_id; hr_vol_status_t status; hr_level_t level; - /* - * SNIA - * Common RAID Disk Data Format - * Specification - * Version 2.0 Revision 19 - */ -#define HR_RLQ_RAID4_0 0x00 /* RAID-4 Non-Rotating Parity 0 */ -#define HR_RLQ_RAID4_N 0x01 /* RAID-4 Non-Rotating Parity N */ -#define HR_RLQ_RAID5_0R 0x00 /* RAID-5 Rotating Parity 0 with Data Restart */ -#define HR_RLQ_RAID5_NR 0x02 /* RAID-5 Rotating Parity N with Data Restart */ -#define HR_RLQ_RAID5_NC 0x03 /* RAID-5 Rotating Parity N with Data Continuation */ uint8_t RLQ; /* RAID Level Qualifier */ char devname[HR_DEVNAME_LEN]; } hr_volume_t; From ea0d494efbfba888ee44f34b87b6fc909f8af787 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 6 Dec 2024 21:20:01 +0100 Subject: [PATCH 090/324] hr: don't set RLQ when assembling --- uspace/srv/bd/hr/hr.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 14d381a6b7..f58acbbca7 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -187,27 +187,31 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) switch (new_volume->level) { case HR_LVL_1: - new_volume->RLQ = 0x00; /* XXX: yet unused */ + if (!assemble) + new_volume->RLQ = 0x00; /* XXX: yet unused */ new_volume->hr_ops.create = hr_raid1_create; new_volume->hr_ops.init = hr_raid1_init; new_volume->hr_ops.status_event = hr_raid1_status_event; new_volume->hr_ops.add_hotspare = hr_raid1_add_hotspare; break; case HR_LVL_0: - new_volume->RLQ = 0x00; + if (!assemble) + new_volume->RLQ = 0x00; new_volume->hr_ops.create = hr_raid0_create; new_volume->hr_ops.init = hr_raid0_init; new_volume->hr_ops.status_event = hr_raid0_status_event; break; case HR_LVL_4: - new_volume->RLQ = HR_RLQ_RAID4_N; + if (!assemble) + new_volume->RLQ = HR_RLQ_RAID4_N; new_volume->hr_ops.create = hr_raid5_create; new_volume->hr_ops.init = hr_raid5_init; new_volume->hr_ops.status_event = hr_raid5_status_event; new_volume->hr_ops.add_hotspare = hr_raid5_add_hotspare; break; case HR_LVL_5: - new_volume->RLQ = HR_RLQ_RAID5_NR; + if (!assemble) + new_volume->RLQ = HR_RLQ_RAID5_NR; new_volume->hr_ops.create = hr_raid5_create; new_volume->hr_ops.init = hr_raid5_init; new_volume->hr_ops.status_event = hr_raid5_status_event; From f312fb9f9e93d59982bec2bfcabeafaaabb2ebbd Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 13 Dec 2024 14:19:12 +0100 Subject: [PATCH 091/324] hr: remove RAID4 functions leftovers --- uspace/srv/bd/hr/var.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index dc83bcea17..3b8d3c61a7 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -94,21 +94,17 @@ extern void hr_fini_devs(hr_volume_t *); extern errno_t hr_raid0_create(hr_volume_t *); extern errno_t hr_raid1_create(hr_volume_t *); -extern errno_t hr_raid4_create(hr_volume_t *); extern errno_t hr_raid5_create(hr_volume_t *); extern errno_t hr_raid0_init(hr_volume_t *); extern errno_t hr_raid1_init(hr_volume_t *); -extern errno_t hr_raid4_init(hr_volume_t *); extern errno_t hr_raid5_init(hr_volume_t *); extern void hr_raid0_status_event(hr_volume_t *); extern void hr_raid1_status_event(hr_volume_t *); -extern void hr_raid4_status_event(hr_volume_t *); extern void hr_raid5_status_event(hr_volume_t *); extern errno_t hr_raid1_add_hotspare(hr_volume_t *, service_id_t); -extern errno_t hr_raid4_add_hotspare(hr_volume_t *, service_id_t); extern errno_t hr_raid5_add_hotspare(hr_volume_t *, service_id_t); #endif From 521b3879c0b26898ffbf9a9b2e9226d4c81a546d Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 16 Dec 2024 19:52:18 +0100 Subject: [PATCH 092/324] hr: RAID5: fix degraded write --- uspace/srv/bd/hr/raid5.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index f02bf69229..50e03ba6a5 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -391,9 +391,11 @@ static errno_t hr_raid5_write(hr_volume_t *vol, uint64_t p_extent, * write new parity */ bool first = true; - for (i = 1; i < vol->extent_no; i++) { + for (i = 0; i < vol->extent_no; i++) { if (i == (size_t)bad) continue; + if (i == p_extent) + continue; if (first) { rc = block_read_direct(vol->extents[i].svc_id, ba, cnt, xorbuf); @@ -600,7 +602,7 @@ static errno_t hr_raid5_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, case HR_BD_READ: retry_read: ssize_t bad = hr_raid5_get_bad_ext(vol); - if (bad > 0 && extent == (size_t)bad) { + if (bad > -1 && extent == (size_t)bad) { rc = hr_raid5_read_degraded(vol, bad, phys_block, data_read, cnt); } else { From 37ffa4dd5c6c689e42e208fc5e38a672082835ae Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 16 Dec 2024 20:32:48 +0100 Subject: [PATCH 093/324] hr: modify change state message --- uspace/srv/bd/hr/util.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index f1a6fa31e7..7a3a358d90 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -206,7 +206,7 @@ void hr_add_ba_offset(hr_volume_t *vol, uint64_t *ba) void hr_update_ext_status(hr_volume_t *vol, size_t extent, hr_ext_status_t s) { hr_ext_status_t old = vol->extents[extent].status; - HR_WARN("\"%s\": changing state of extent %lu: %s -> %s\n", + HR_WARN("\"%s\": changing extent %lu state: %s -> %s\n", vol->devname, extent, hr_get_ext_status_msg(old), hr_get_ext_status_msg(s)); vol->extents[extent].status = s; @@ -215,7 +215,7 @@ void hr_update_ext_status(hr_volume_t *vol, size_t extent, hr_ext_status_t s) void hr_update_hotspare_status(hr_volume_t *vol, size_t hs, hr_ext_status_t s) { hr_ext_status_t old = vol->hotspares[hs].status; - HR_WARN("\"%s\": changing state of hotspare %lu: %s -> %s\n", + HR_WARN("\"%s\": changing hotspare %lu state: %s -> %s\n", vol->devname, hs, hr_get_ext_status_msg(old), hr_get_ext_status_msg(s)); vol->hotspares[hs].status = s; @@ -223,7 +223,7 @@ void hr_update_hotspare_status(hr_volume_t *vol, size_t hs, hr_ext_status_t s) void hr_update_vol_status(hr_volume_t *vol, hr_vol_status_t s) { - HR_WARN("\"%s\": changing state: %s -> %s\n", vol->devname, + HR_WARN("\"%s\": changing volume state: %s -> %s\n", vol->devname, hr_get_vol_status_msg(vol->status), hr_get_vol_status_msg(s)); vol->status = s; } From 2876911712f264ffbcd42355d6eb9523cc3eed7b Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 16 Dec 2024 21:11:47 +0100 Subject: [PATCH 094/324] hrctl: usage string modification --- uspace/app/hrctl/hrctl.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index 6260ae9d02..ad092d8125 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -57,8 +57,9 @@ static const char usage_str[] = " sample file at: " HRCTL_SAMPLE_CONFIG_PATH "\n" " -A, --assemble-file=PATH create an array from file\n" " -s, --status display status of active arrays\n" + " -H, --hotspare=DEV add hotspare extent\n" " -D, --destroy destroy/disassemble an active array\n" - " -F, --fail-extent fail an extent, use with -T and set it before\n" + " -F, --fail-extent fail an extent, use with -D and set it before\n" " -c, --create=NAME create new array\n" " -a, --assemble=NAME assemble an existing array\n" " -n non-zero number of devices\n" @@ -68,7 +69,6 @@ static const char usage_str[] = " -1 mirroring\n" " -4 parity on one extent\n" " -5 distributed parity\n" - " -H, --hotspare=DEV add hotspare extent\n" "\n" "When specifying name for creation or assembly, the device name\n" "is automatically prepended with \"devices/\" prefix.\n" @@ -82,6 +82,8 @@ static const char usage_str[] = " that were previously in an array\n" " hrctl devices/hr0 --hotspare=devices/disk10\n" " - adds \"devices/disk10\" as hotspare extent\n" + " hrctl -F 0 -D devices/hr0\n" + " - marks first extent as FAILED\n" "Limitations:\n" " - device name must be less than 32 characters in size\n"; From f7257870f3b7481e23d50317fe1f7d861207f733 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 22 Dec 2024 11:25:00 +0100 Subject: [PATCH 095/324] hr: fge: fibril group executor This fibril pool allows execution of grouped work units, providing pre-allocated storage for the workers. Based on an idea from Vojtech Horky. --- uspace/srv/bd/hr/fge.c | 471 +++++++++++++++++++++++++++++++++++ uspace/srv/bd/hr/fge.h | 65 +++++ uspace/srv/bd/hr/meson.build | 10 +- 3 files changed, 545 insertions(+), 1 deletion(-) create mode 100644 uspace/srv/bd/hr/fge.c create mode 100644 uspace/srv/bd/hr/fge.h diff --git a/uspace/srv/bd/hr/fge.c b/uspace/srv/bd/hr/fge.c new file mode 100644 index 0000000000..363b97301b --- /dev/null +++ b/uspace/srv/bd/hr/fge.c @@ -0,0 +1,471 @@ +/* + * Copyright (c) 2024 Miroslav Cimerman + * Copyright (c) 2024 Vojtech Horky + * 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 + * @brief Fibril group executor + * + * Fibril pool with pre-allocated storage allowing + * execution of groups consisting of multiple work + * units. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fge.h" + +struct fge_fibril_data; +typedef struct fge_fibril_data fge_fibril_data_t; +struct wu_queue; +typedef struct wu_queue wu_queue_t; + +static void *hr_fpool_make_storage(hr_fpool_t *, ssize_t *); +static errno_t fge_fibril(void *); +static errno_t wu_queue_init(wu_queue_t *, size_t); +static void wu_queue_push(wu_queue_t *, fge_fibril_data_t); +static fge_fibril_data_t wu_queue_pop(wu_queue_t *); +static ssize_t hr_fpool_get_free_slot(hr_fpool_t *); + +typedef struct fge_fibril_data { + hr_wu_t wu; /* user-provided work unit fcn pointer */ + void *arg; + hr_fgroup_t *group; + ssize_t memslot; /* index to pool bitmap slot */ +} fge_fibril_data_t; + +typedef struct wu_queue { + fibril_mutex_t lock; + fibril_condvar_t not_empty; + fibril_condvar_t not_full; + fge_fibril_data_t *fexecs; + size_t capacity; + size_t size; + size_t front; + size_t back; +} wu_queue_t; + +struct hr_fpool { + fibril_mutex_t lock; + fibril_condvar_t all_wus_done; + bitmap_t bitmap; + wu_queue_t queue; + fid_t *fibrils; + uint8_t *wu_storage; + size_t fibril_cnt; + size_t max_wus; + size_t active_groups; + bool stop; + size_t wu_size; + size_t wu_storage_free_count; +}; + +struct hr_fgroup { + hr_fpool_t *pool; + size_t wu_cnt; /* total wu count */ + size_t submitted; + size_t reserved_cnt; /* no. of reserved wu storage slots */ + size_t reserved_avail; + size_t *memslots; /* indices to pool bitmap */ + void *own_mem; + size_t own_used; + errno_t final_errno; + atomic_size_t finished_okay; + atomic_size_t finished_fail; + atomic_size_t wus_started; + fibril_mutex_t lock; + fibril_condvar_t all_done; +}; + +hr_fpool_t *hr_fpool_create(size_t fibril_cnt, size_t max_wus, + size_t wu_storage_size) +{ + void *bitmap_data = NULL; + + hr_fpool_t *result = calloc(1, sizeof(hr_fpool_t)); + if (result == NULL) + return NULL; + + result->fibrils = malloc(sizeof(fid_t) * fibril_cnt); + if (result->fibrils == NULL) + goto bad; + + result->wu_storage = malloc(wu_storage_size * max_wus); + if (result->wu_storage == NULL) + goto bad; + + bitmap_data = calloc(1, bitmap_size(max_wus)); + if (bitmap_data == NULL) + goto bad; + bitmap_initialize(&result->bitmap, max_wus, bitmap_data); + + if (wu_queue_init(&result->queue, max_wus) != EOK) + goto bad; + + fibril_mutex_initialize(&result->lock); + fibril_condvar_initialize(&result->all_wus_done); + + result->max_wus = max_wus; + result->fibril_cnt = fibril_cnt; + result->wu_size = wu_storage_size; + result->wu_storage_free_count = max_wus; + result->stop = false; + result->active_groups = 0; + + for (size_t i = 0; i < fibril_cnt; i++) { + result->fibrils[i] = fibril_create(fge_fibril, result); + fibril_start(result->fibrils[i]); + } + + return result; +bad: + if (result->queue.fexecs) + free(result->queue.fexecs); + if (bitmap_data) + free(bitmap_data); + if (result->wu_storage) + free(result->wu_storage); + if (result->fibrils) + free(result->fibrils); + free(result); + + return NULL; +} + +void hr_fpool_destroy(hr_fpool_t *pool) +{ + fibril_mutex_lock(&pool->lock); + pool->stop = true; + while (pool->active_groups > 0) + fibril_condvar_wait(&pool->all_wus_done, &pool->lock); + + fibril_mutex_unlock(&pool->lock); + + free(pool->bitmap.bits); + free(pool->queue.fexecs); + free(pool->wu_storage); + free(pool->fibrils); + free(pool); +} + +static void *hr_fpool_make_storage(hr_fpool_t *pool, ssize_t *rmemslot) +{ + fibril_mutex_lock(&pool->lock); + ssize_t memslot = hr_fpool_get_free_slot(pool); + assert(memslot != -1); + + bitmap_set(&pool->bitmap, memslot, 1); + + fibril_mutex_unlock(&pool->lock); + + if (rmemslot) + *rmemslot = memslot; + + return pool->wu_storage + pool->wu_size * memslot; +} + +hr_fgroup_t *hr_fgroup_create(hr_fpool_t *parent, size_t wu_cnt) +{ + hr_fgroup_t *result = malloc(sizeof(hr_fgroup_t)); + if (result == NULL) + return NULL; + + result->reserved_cnt = 0; + result->own_mem = NULL; + result->memslots = NULL; + + fibril_mutex_lock(&parent->lock); + + parent->active_groups++; + + if (parent->wu_storage_free_count >= wu_cnt) { + parent->wu_storage_free_count -= wu_cnt; + result->reserved_cnt = wu_cnt; + } else { + /* + * Could be more conservative with memory here and + * allocate space only for one work unit and execute + * work units sequentially like it was first intended with + * the fallback storage. + */ + size_t taking = parent->wu_storage_free_count; + result->own_mem = malloc(parent->wu_size * (wu_cnt - taking)); + result->reserved_cnt = taking; + parent->wu_storage_free_count = 0; + if (result->own_mem == NULL) + goto bad; + } + + if (result->reserved_cnt > 0) { + result->memslots = + malloc(sizeof(size_t) * result->reserved_cnt); + if (result->memslots == NULL) + goto bad; + } + + fibril_mutex_unlock(&parent->lock); + + result->pool = parent; + result->wu_cnt = wu_cnt; + result->submitted = 0; + result->reserved_avail = result->reserved_cnt; + result->own_used = 0; + result->final_errno = EOK; + result->finished_okay = 0; + result->finished_fail = 0; + result->wus_started = 0; + + fibril_mutex_initialize(&result->lock); + fibril_condvar_initialize(&result->all_done); + + return result; + +bad: + fibril_mutex_lock(&parent->lock); + parent->wu_storage_free_count += result->reserved_cnt; + fibril_mutex_unlock(&parent->lock); + + if (result->memslots) + free(result->memslots); + if (result->own_mem) + free(result->own_mem); + free(result); + + return NULL; +} + +void *hr_fgroup_alloc(hr_fgroup_t *group) +{ + void *storage; + + fibril_mutex_lock(&group->lock); + + if (group->reserved_avail > 0) { + ssize_t memslot; + storage = hr_fpool_make_storage(group->pool, &memslot); + assert(storage != NULL); + group->reserved_avail--; + group->memslots[group->submitted] = memslot; + } else { + storage = + group->own_mem + group->pool->wu_size * group->own_used; + group->own_used++; + } + + fibril_mutex_unlock(&group->lock); + + return storage; +} + +void hr_fgroup_submit(hr_fgroup_t *group, hr_wu_t wu, void *arg) +{ + fibril_mutex_lock(&group->lock); + assert(group->submitted + 1 <= group->wu_cnt); + + fge_fibril_data_t executor; + executor.wu = wu; + executor.arg = arg; + executor.group = group; + + if (group->submitted < group->reserved_cnt) + executor.memslot = group->memslots[group->submitted]; + else + executor.memslot = -1; + + group->submitted++; + fibril_mutex_unlock(&group->lock); + + wu_queue_push(&group->pool->queue, executor); +} + +static void hr_fpool_group_epilogue(hr_fpool_t *pool) +{ + fibril_mutex_lock(&pool->lock); + + pool->active_groups--; + if (pool->active_groups == 0) + fibril_condvar_signal(&pool->all_wus_done); + + fibril_mutex_unlock(&pool->lock); +} + +errno_t hr_fgroup_wait(hr_fgroup_t *group, size_t *rfailed) +{ + fibril_mutex_lock(&group->lock); + while (true) { + size_t finished = group->finished_fail + group->finished_okay; + if (group->wus_started != 0 && group->wus_started == finished) + break; + + fibril_condvar_wait(&group->all_done, &group->lock); + } + + if (rfailed) { + *rfailed = group->finished_fail; + } + + errno_t rc = EOK; + if (group->finished_okay != group->wus_started) + rc = EIO; + + fibril_mutex_unlock(&group->lock); + + hr_fpool_group_epilogue(group->pool); + + if (group->memslots) + free(group->memslots); + if (group->own_mem) + free(group->own_mem); + free(group); + + return rc; +} + +static errno_t fge_fibril(void *arg) +{ + hr_fpool_t *pool = arg; + while (true) { + fge_fibril_data_t executor; + fibril_mutex_lock(&pool->lock); + + while (pool->queue.size == 0 && !pool->stop) { + fibril_condvar_wait(&pool->queue.not_empty, + &pool->lock); + } + + if (pool->stop && pool->queue.size == 0) { + fibril_mutex_unlock(&pool->lock); + break; + } + + executor = wu_queue_pop(&pool->queue); + + fibril_mutex_unlock(&pool->lock); + + hr_fgroup_t *group = executor.group; + + atomic_fetch_add_explicit(&group->wus_started, 1, + memory_order_relaxed); + + errno_t rc = executor.wu(executor.arg); + + if (rc == EOK) + atomic_fetch_add_explicit(&group->finished_okay, 1, + memory_order_relaxed); + else + atomic_fetch_add_explicit(&group->finished_fail, 1, + memory_order_relaxed); + + fibril_mutex_lock(&pool->lock); + if (executor.memslot > -1) { + bitmap_set(&pool->bitmap, executor.memslot, 0); + pool->wu_storage_free_count++; + } + + size_t group_total_done = group->finished_fail + + group->finished_okay; + if (group->wus_started == group_total_done) + fibril_condvar_signal(&group->all_done); + + fibril_mutex_unlock(&pool->lock); + } + return EOK; +} + +static errno_t wu_queue_init(wu_queue_t *queue, size_t capacity) +{ + queue->fexecs = malloc(sizeof(fge_fibril_data_t) * capacity); + if (queue->fexecs == NULL) + return ENOMEM; + + queue->capacity = capacity; + queue->size = 0; + queue->front = 0; + queue->back = 0; + fibril_mutex_initialize(&queue->lock); + fibril_condvar_initialize(&queue->not_empty); + fibril_condvar_initialize(&queue->not_full); + + return EOK; +} + +static void wu_queue_push(wu_queue_t *queue, fge_fibril_data_t executor) +{ + fibril_mutex_lock(&queue->lock); + + while (queue->size == queue->capacity) + fibril_condvar_wait(&queue->not_full, &queue->lock); + + queue->fexecs[queue->back] = executor; + queue->back = (queue->back + 1) % queue->capacity; + queue->size++; + + fibril_condvar_signal(&queue->not_empty); + + fibril_mutex_unlock(&queue->lock); +} + +static fge_fibril_data_t wu_queue_pop(wu_queue_t *queue) +{ + fibril_mutex_lock(&queue->lock); + + while (queue->size == 0) + fibril_condvar_wait(&queue->not_empty, &queue->lock); + + fge_fibril_data_t wu = queue->fexecs[queue->front]; + queue->front = (queue->front + 1) % queue->capacity; + queue->size--; + + fibril_condvar_signal(&queue->not_full); + + fibril_mutex_unlock(&queue->lock); + return wu; +} + +static ssize_t hr_fpool_get_free_slot(hr_fpool_t *pool) +{ + bitmap_t *bitmap = &pool->bitmap; + for (size_t i = 0; i < pool->max_wus; i++) + if (!bitmap_get(bitmap, i)) + return i; + return -1; +} + +/** @} + */ diff --git a/uspace/srv/bd/hr/fge.h b/uspace/srv/bd/hr/fge.h new file mode 100644 index 0000000000..6e23c70741 --- /dev/null +++ b/uspace/srv/bd/hr/fge.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2024 Miroslav Cimerman + * Copyright (c) 2024 Vojtech Horky + * 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 + * @brief Fibril group executor + * + * Fibril pool with pre-allocated storage allowing + * execution of groups consisting of multiple work + * units. + */ + +#ifndef _HR_FGE_H +#define _HR_FGE_H + +#include +#include + +struct hr_fpool; +typedef struct hr_fpool hr_fpool_t; +struct hr_fgroup; +typedef struct hr_fgroup hr_fgroup_t; + +typedef errno_t (*hr_wu_t)(void *); + +extern hr_fpool_t *hr_fpool_create(size_t, size_t, size_t); +extern void hr_fpool_destroy(hr_fpool_t *); +extern hr_fgroup_t *hr_fgroup_create(hr_fpool_t *, size_t); +extern void *hr_fgroup_alloc(hr_fgroup_t *); +extern void hr_fgroup_submit(hr_fgroup_t *, hr_wu_t, void *); +extern errno_t hr_fgroup_wait(hr_fgroup_t *, size_t *); + +#endif + +/** @} + */ diff --git a/uspace/srv/bd/hr/meson.build b/uspace/srv/bd/hr/meson.build index 5ff018c497..34f26af681 100644 --- a/uspace/srv/bd/hr/meson.build +++ b/uspace/srv/bd/hr/meson.build @@ -27,4 +27,12 @@ # deps = [ 'block', 'device' ] -src = files('hr.c', 'raid0.c', 'raid1.c', 'raid5.c', 'superblock.c', 'util.c') +src = files( + 'fge.c', + 'hr.c', + 'raid0.c', + 'raid1.c', + 'raid5.c', + 'superblock.c', + 'util.c' + ) From 38e3c0a71c979f993a92692cc2238b2abbdbc386 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 22 Dec 2024 16:35:54 +0100 Subject: [PATCH 096/324] hr: range locks --- uspace/srv/bd/hr/util.c | 103 ++++++++++++++++++++++++++++++++++++++-- uspace/srv/bd/hr/util.h | 3 ++ uspace/srv/bd/hr/var.h | 15 ++++++ 3 files changed, 118 insertions(+), 3 deletions(-) diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 7a3a358d90..3c87d113e6 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -33,8 +33,10 @@ * @file */ +#include #include #include +#include #include #include #include @@ -45,6 +47,12 @@ #include "util.h" #include "var.h" +#define HR_RL_LIST_LOCK(vol) (fibril_mutex_lock(&vol->range_lock_list_lock)) +#define HR_RL_LIST_UNLOCK(vol) \ + (fibril_mutex_unlock(&vol->range_lock_list_lock)) + +static bool hr_range_lock_overlap(hr_range_lock_t *, hr_range_lock_t *); + extern loc_srv_t *hr_srv; errno_t hr_init_devs(hr_volume_t *vol) @@ -127,7 +135,6 @@ errno_t hr_register_volume(hr_volume_t *vol) } vol->svc_id = new_id; - error: free(fullname); return rc; @@ -257,13 +264,103 @@ void hr_sync_all_extents(hr_volume_t *vol) size_t hr_count_extents(hr_volume_t *vol, hr_ext_status_t status) { size_t count = 0; - for (size_t i = 0; i < vol->extent_no; i++) { + for (size_t i = 0; i < vol->extent_no; i++) if (vol->extents[i].status == status) count++; - } return count; } +hr_range_lock_t *hr_range_lock_acquire(hr_volume_t *vol, uint64_t ba, + uint64_t cnt) +{ + hr_range_lock_t *rl = malloc(sizeof(hr_range_lock_t)); + if (rl == NULL) + return NULL; + + rl->vol = vol; + rl->off = ba; + rl->len = cnt; + + rl->pending = 1; + rl->ignore = false; + + link_initialize(&rl->link); + fibril_mutex_initialize(&rl->lock); + + fibril_mutex_lock(&rl->lock); + +again: + HR_RL_LIST_LOCK(vol); + list_foreach(vol->range_lock_list, link, hr_range_lock_t, rlp) { + if (rlp->ignore) + continue; + if (hr_range_lock_overlap(rlp, rl)) { + rlp->pending++; + + HR_RL_LIST_UNLOCK(vol); + + fibril_mutex_lock(&rlp->lock); + + HR_RL_LIST_LOCK(vol); + + rlp->pending--; + + /* + * when ignore is set, after HR_RL_LIST_UNLOCK(), + * noone new is going to be able to start sleeping + * on the ignored range lock, only already waiting + * IOs will come through here + */ + rlp->ignore = true; + + fibril_mutex_unlock(&rlp->lock); + + if (rlp->pending == 0) { + list_remove(&rlp->link); + free(rlp); + } + + HR_RL_LIST_UNLOCK(vol); + goto again; + } + } + + list_append(&rl->link, &vol->range_lock_list); + + HR_RL_LIST_UNLOCK(vol); + return rl; +} + +void hr_range_lock_release(hr_range_lock_t *rl) +{ + HR_RL_LIST_LOCK(rl->vol); + + rl->pending--; + + fibril_mutex_unlock(&rl->lock); + + if (rl->pending == 0) { + list_remove(&rl->link); + free(rl); + } + + HR_RL_LIST_UNLOCK(rl->vol); +} + +static bool hr_range_lock_overlap(hr_range_lock_t *rl1, hr_range_lock_t *rl2) +{ + uint64_t rl1_start = rl1->off; + uint64_t rl1_end = rl1->off + rl1->len - 1; + uint64_t rl2_start = rl2->off; + uint64_t rl2_end = rl2->off + rl2->len - 1; + + /* one ends before the other starts */ + if (rl1_end < rl2_start || rl2_end < rl1_start) + return false; + + return true; +} + /** @} */ diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index b4613574ae..352f68d91c 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -60,6 +60,9 @@ extern void hr_update_hotspare_status(hr_volume_t *, size_t, hr_ext_status_t); extern void hr_update_vol_status(hr_volume_t *, hr_vol_status_t); extern void hr_sync_all_extents(hr_volume_t *); extern size_t hr_count_extents(hr_volume_t *, hr_ext_status_t); +extern hr_range_lock_t *hr_range_lock_acquire(hr_volume_t *, uint64_t, + uint64_t); +extern void hr_range_lock_release(hr_range_lock_t *rl); #endif diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index 3b8d3c61a7..05f0d76635 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -36,8 +36,10 @@ #ifndef _HR_VAR_H #define _HR_VAR_H +#include #include #include +#include #include #define NAME "hr" @@ -60,6 +62,9 @@ typedef struct hr_volume { link_t lvolumes; fibril_mutex_t lock; + list_t range_lock_list; + fibril_mutex_t range_lock_list_lock; + size_t extent_no; hr_extent_t extents[HR_MAX_EXTENTS]; @@ -89,6 +94,16 @@ typedef enum { HR_BD_WRITE } hr_bd_op_type_t; +typedef struct hr_range_lock { + fibril_mutex_t lock; + link_t link; + hr_volume_t *vol; + uint64_t off; + uint64_t len; + size_t pending; /* protected by vol->range_lock_list_lock */ + bool ignore; /* protected by vol->range_lock_list_lock */ +} hr_range_lock_t; + extern errno_t hr_init_devs(hr_volume_t *); extern void hr_fini_devs(hr_volume_t *); From 83c8bb22d767b2675ad7a54db9e3856c1018568e Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 22 Dec 2024 16:37:02 +0100 Subject: [PATCH 097/324] hr: hr_volume_t: fix number of hotspares --- uspace/srv/bd/hr/var.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index 05f0d76635..5ef720e457 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -69,7 +69,7 @@ typedef struct hr_volume { hr_extent_t extents[HR_MAX_EXTENTS]; size_t hotspare_no; - hr_extent_t hotspares[HR_MAX_EXTENTS]; + hr_extent_t hotspares[HR_MAX_HOTSPARES]; size_t bsize; uint64_t nblocks; From 57110ac8be5f41fb6862492a5c74b85a9444d016 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 22 Dec 2024 22:31:46 +0100 Subject: [PATCH 098/324] hr: initialize range lock list and list lock --- uspace/srv/bd/hr/hr.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index f58acbbca7..164877b751 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -235,6 +235,9 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) fibril_mutex_initialize(&new_volume->lock); + list_initialize(&new_volume->range_lock_list); + fibril_mutex_initialize(&new_volume->range_lock_list_lock); + rc = new_volume->hr_ops.create(new_volume); if (rc != EOK) goto error; From 95158dac9177125617b97aec642b7998df7a04d8 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 22 Dec 2024 22:32:28 +0100 Subject: [PATCH 099/324] hr: fge: can ask for wus that finished with EOK --- uspace/srv/bd/hr/fge.c | 7 ++++--- uspace/srv/bd/hr/fge.h | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/uspace/srv/bd/hr/fge.c b/uspace/srv/bd/hr/fge.c index 363b97301b..12816864e3 100644 --- a/uspace/srv/bd/hr/fge.c +++ b/uspace/srv/bd/hr/fge.c @@ -325,7 +325,7 @@ static void hr_fpool_group_epilogue(hr_fpool_t *pool) fibril_mutex_unlock(&pool->lock); } -errno_t hr_fgroup_wait(hr_fgroup_t *group, size_t *rfailed) +errno_t hr_fgroup_wait(hr_fgroup_t *group, size_t *rokay, size_t *rfailed) { fibril_mutex_lock(&group->lock); while (true) { @@ -336,9 +336,10 @@ errno_t hr_fgroup_wait(hr_fgroup_t *group, size_t *rfailed) fibril_condvar_wait(&group->all_done, &group->lock); } - if (rfailed) { + if (rokay) + *rokay = group->finished_okay; + if (rfailed) *rfailed = group->finished_fail; - } errno_t rc = EOK; if (group->finished_okay != group->wus_started) diff --git a/uspace/srv/bd/hr/fge.h b/uspace/srv/bd/hr/fge.h index 6e23c70741..026c8dd097 100644 --- a/uspace/srv/bd/hr/fge.h +++ b/uspace/srv/bd/hr/fge.h @@ -57,7 +57,7 @@ extern void hr_fpool_destroy(hr_fpool_t *); extern hr_fgroup_t *hr_fgroup_create(hr_fpool_t *, size_t); extern void *hr_fgroup_alloc(hr_fgroup_t *); extern void hr_fgroup_submit(hr_fgroup_t *, hr_wu_t, void *); -extern errno_t hr_fgroup_wait(hr_fgroup_t *, size_t *); +extern errno_t hr_fgroup_wait(hr_fgroup_t *, size_t *, size_t *); #endif From f3b74d1f4844a457542edfd3753dc67fbd3ed14c Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 22 Dec 2024 23:40:22 +0100 Subject: [PATCH 100/324] hr: fge: use libc queue --- uspace/srv/bd/hr/fge.c | 46 ++++++++++++++++-------------------------- uspace/srv/bd/hr/fge.h | 5 ----- 2 files changed, 17 insertions(+), 34 deletions(-) diff --git a/uspace/srv/bd/hr/fge.c b/uspace/srv/bd/hr/fge.c index 12816864e3..bc0011c9ef 100644 --- a/uspace/srv/bd/hr/fge.c +++ b/uspace/srv/bd/hr/fge.c @@ -40,6 +40,7 @@ */ #include +#include #include #include #include @@ -59,8 +60,8 @@ typedef struct wu_queue wu_queue_t; static void *hr_fpool_make_storage(hr_fpool_t *, ssize_t *); static errno_t fge_fibril(void *); static errno_t wu_queue_init(wu_queue_t *, size_t); -static void wu_queue_push(wu_queue_t *, fge_fibril_data_t); -static fge_fibril_data_t wu_queue_pop(wu_queue_t *); +static void wu_queue_push(wu_queue_t *, fge_fibril_data_t *); +static void wu_queue_pop(wu_queue_t *, fge_fibril_data_t *); static ssize_t hr_fpool_get_free_slot(hr_fpool_t *); typedef struct fge_fibril_data { @@ -75,10 +76,7 @@ typedef struct wu_queue { fibril_condvar_t not_empty; fibril_condvar_t not_full; fge_fibril_data_t *fexecs; - size_t capacity; - size_t size; - size_t front; - size_t back; + circ_buf_t cbuf; } wu_queue_t; struct hr_fpool { @@ -311,7 +309,7 @@ void hr_fgroup_submit(hr_fgroup_t *group, hr_wu_t wu, void *arg) group->submitted++; fibril_mutex_unlock(&group->lock); - wu_queue_push(&group->pool->queue, executor); + wu_queue_push(&group->pool->queue, &executor); } static void hr_fpool_group_epilogue(hr_fpool_t *pool) @@ -365,17 +363,17 @@ static errno_t fge_fibril(void *arg) fge_fibril_data_t executor; fibril_mutex_lock(&pool->lock); - while (pool->queue.size == 0 && !pool->stop) { + while (circ_buf_nused(&pool->queue.cbuf) == 0 && !pool->stop) { fibril_condvar_wait(&pool->queue.not_empty, &pool->lock); } - if (pool->stop && pool->queue.size == 0) { + if (pool->stop && circ_buf_nused(&pool->queue.cbuf) == 0) { fibril_mutex_unlock(&pool->lock); break; } - executor = wu_queue_pop(&pool->queue); + wu_queue_pop(&pool->queue, &executor); fibril_mutex_unlock(&pool->lock); @@ -409,16 +407,15 @@ static errno_t fge_fibril(void *arg) return EOK; } -static errno_t wu_queue_init(wu_queue_t *queue, size_t capacity) +static errno_t wu_queue_init(wu_queue_t *queue, size_t nmemb) { - queue->fexecs = malloc(sizeof(fge_fibril_data_t) * capacity); + queue->fexecs = malloc(sizeof(fge_fibril_data_t) * nmemb); if (queue->fexecs == NULL) return ENOMEM; - queue->capacity = capacity; - queue->size = 0; - queue->front = 0; - queue->back = 0; + circ_buf_init(&queue->cbuf, queue->fexecs, nmemb, + sizeof(fge_fibril_data_t)); + fibril_mutex_initialize(&queue->lock); fibril_condvar_initialize(&queue->not_empty); fibril_condvar_initialize(&queue->not_full); @@ -426,37 +423,28 @@ static errno_t wu_queue_init(wu_queue_t *queue, size_t capacity) return EOK; } -static void wu_queue_push(wu_queue_t *queue, fge_fibril_data_t executor) +static void wu_queue_push(wu_queue_t *queue, fge_fibril_data_t *executor) { fibril_mutex_lock(&queue->lock); - while (queue->size == queue->capacity) + while (circ_buf_push(&queue->cbuf, executor) == EAGAIN) fibril_condvar_wait(&queue->not_full, &queue->lock); - queue->fexecs[queue->back] = executor; - queue->back = (queue->back + 1) % queue->capacity; - queue->size++; - fibril_condvar_signal(&queue->not_empty); fibril_mutex_unlock(&queue->lock); } -static fge_fibril_data_t wu_queue_pop(wu_queue_t *queue) +static void wu_queue_pop(wu_queue_t *queue, fge_fibril_data_t *executor) { fibril_mutex_lock(&queue->lock); - while (queue->size == 0) + while (circ_buf_pop(&queue->cbuf, executor) == EAGAIN) fibril_condvar_wait(&queue->not_empty, &queue->lock); - fge_fibril_data_t wu = queue->fexecs[queue->front]; - queue->front = (queue->front + 1) % queue->capacity; - queue->size--; - fibril_condvar_signal(&queue->not_full); fibril_mutex_unlock(&queue->lock); - return wu; } static ssize_t hr_fpool_get_free_slot(hr_fpool_t *pool) diff --git a/uspace/srv/bd/hr/fge.h b/uspace/srv/bd/hr/fge.h index 026c8dd097..a2652ea751 100644 --- a/uspace/srv/bd/hr/fge.h +++ b/uspace/srv/bd/hr/fge.h @@ -32,11 +32,6 @@ */ /** * @file - * @brief Fibril group executor - * - * Fibril pool with pre-allocated storage allowing - * execution of groups consisting of multiple work - * units. */ #ifndef _HR_FGE_H From 6784abcc49550b0cd5dbc158b309eccd974ef3d8 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 22 Dec 2024 23:42:05 +0100 Subject: [PATCH 101/324] hr: hr_sess_init(): don't use IPC_FLAG_BLOCKING --- uspace/lib/device/src/hr.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index ee9fca6edf..edb9cbf302 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -55,14 +55,13 @@ errno_t hr_sess_init(hr_t **rhr) service_id_t hr_svcid; - rc = loc_service_get_id(SERVICE_NAME_HR, &hr_svcid, IPC_FLAG_BLOCKING); + rc = loc_service_get_id(SERVICE_NAME_HR, &hr_svcid, 0); if (rc != EOK) { rc = EIO; goto error; } - hr->sess = loc_service_connect(hr_svcid, INTERFACE_HR, - IPC_FLAG_BLOCKING); + hr->sess = loc_service_connect(hr_svcid, INTERFACE_HR, 0); if (hr->sess == NULL) { rc = EIO; goto error; From 37a9c1e3083eac96370742d31a43475ce5727b1d Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 23 Dec 2024 12:06:35 +0100 Subject: [PATCH 102/324] hr: hr_volume_t: rename RLQ -> layout --- uspace/lib/device/include/hr.h | 2 +- uspace/lib/device/src/hr.c | 12 ++++++------ uspace/srv/bd/hr/hr.c | 10 +++++----- uspace/srv/bd/hr/raid5.c | 30 +++++++++++++++--------------- uspace/srv/bd/hr/superblock.c | 4 ++-- uspace/srv/bd/hr/var.h | 2 +- 6 files changed, 30 insertions(+), 30 deletions(-) diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index abc0a7b6b5..a6f235f0ae 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -108,7 +108,7 @@ typedef struct hr_vol_info { uint32_t strip_size; size_t bsize; hr_vol_status_t status; - uint8_t RLQ; + uint8_t layout; } hr_vol_info_t; extern errno_t hr_sess_init(hr_t **); diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index edb9cbf302..921dec838b 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -133,7 +133,7 @@ static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info) printf("level: %d\n", vol_info->level); if (vol_info->level == HR_LVL_4 || vol_info->level == HR_LVL_5) { printf("layout: %s\n", - hr_get_layout_str(vol_info->level, vol_info->RLQ)); + hr_get_layout_str(vol_info->level, vol_info->layout)); } if (vol_info->level == HR_LVL_0 || vol_info->level == HR_LVL_4) { if (vol_info->strip_size / 1024 < 1) @@ -162,9 +162,9 @@ static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info) return rc; } if (vol_info->level == HR_LVL_4) { - if ((i == 0 && vol_info->RLQ == HR_RLQ_RAID4_0) || + if ((i == 0 && vol_info->layout == HR_RLQ_RAID4_0) || (i == vol_info->extent_no - 1 && - vol_info->RLQ == HR_RLQ_RAID4_N)) + vol_info->layout == HR_RLQ_RAID4_N)) printf(" P %s %zu %s\n", hr_get_ext_status_msg(ext->status), i, devname); else printf(" %s %zu %s\n", hr_get_ext_status_msg(ext->status), i, devname); @@ -349,11 +349,11 @@ const char *hr_get_ext_status_msg(hr_ext_status_t status) } } -const char *hr_get_layout_str(hr_level_t level, uint8_t RLQ) +const char *hr_get_layout_str(hr_level_t level, uint8_t layout) { switch (level) { case HR_LVL_4: - switch (RLQ) { + switch (layout) { case HR_RLQ_RAID4_0: return "RAID-4 Non-Rotating Parity 0"; case HR_RLQ_RAID4_N: @@ -362,7 +362,7 @@ const char *hr_get_layout_str(hr_level_t level, uint8_t RLQ) return "RAID-4 INVALID"; } case HR_LVL_5: - switch (RLQ) { + switch (layout) { case HR_RLQ_RAID5_0R: return "RAID-5 Rotating Parity 0 with Data Restart"; case HR_RLQ_RAID5_NR: diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 164877b751..f6e395c148 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -188,7 +188,7 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) switch (new_volume->level) { case HR_LVL_1: if (!assemble) - new_volume->RLQ = 0x00; /* XXX: yet unused */ + new_volume->layout = 0x00; /* XXX: yet unused */ new_volume->hr_ops.create = hr_raid1_create; new_volume->hr_ops.init = hr_raid1_init; new_volume->hr_ops.status_event = hr_raid1_status_event; @@ -196,14 +196,14 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) break; case HR_LVL_0: if (!assemble) - new_volume->RLQ = 0x00; + new_volume->layout = 0x00; new_volume->hr_ops.create = hr_raid0_create; new_volume->hr_ops.init = hr_raid0_init; new_volume->hr_ops.status_event = hr_raid0_status_event; break; case HR_LVL_4: if (!assemble) - new_volume->RLQ = HR_RLQ_RAID4_N; + new_volume->layout = HR_RLQ_RAID4_N; new_volume->hr_ops.create = hr_raid5_create; new_volume->hr_ops.init = hr_raid5_init; new_volume->hr_ops.status_event = hr_raid5_status_event; @@ -211,7 +211,7 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) break; case HR_LVL_5: if (!assemble) - new_volume->RLQ = HR_RLQ_RAID5_NR; + new_volume->layout = HR_RLQ_RAID5_NR; new_volume->hr_ops.create = hr_raid5_create; new_volume->hr_ops.init = hr_raid5_init; new_volume->hr_ops.status_event = hr_raid5_status_event; @@ -372,7 +372,7 @@ static void hr_print_status_srv(ipc_call_t *icall) info.strip_size = vol->strip_size; info.bsize = vol->bsize; info.status = vol->status; - info.RLQ = vol->RLQ; + info.layout = vol->layout; if (!async_data_read_receive(&call, &size)) { rc = EREFUSED; diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 50e03ba6a5..4f6f233911 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -532,7 +532,7 @@ static errno_t hr_raid5_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, if (rc != EOK) return rc; - uint8_t RLQ = vol->RLQ; + uint8_t layout = vol->layout; hr_level_t level = vol->level; uint64_t strip_size = vol->strip_size / vol->bsize; /* in blocks */ @@ -540,14 +540,14 @@ static errno_t hr_raid5_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, /* parity extent */ uint64_t p_extent; - if (level == HR_LVL_4 && RLQ == HR_RLQ_RAID4_0) { + if (level == HR_LVL_4 && layout == HR_RLQ_RAID4_0) { p_extent = 0; - } else if (level == HR_LVL_4 && RLQ == HR_RLQ_RAID4_N) { + } else if (level == HR_LVL_4 && layout == HR_RLQ_RAID4_N) { p_extent = vol->extent_no - 1; - } else if (level == HR_LVL_5 && RLQ == HR_RLQ_RAID5_0R) { + } else if (level == HR_LVL_5 && layout == HR_RLQ_RAID5_0R) { p_extent = (stripe / (vol->extent_no - 1)) % vol->extent_no; } else if (level == HR_LVL_5 && - (RLQ == HR_RLQ_RAID5_NR || RLQ == HR_RLQ_RAID5_NC)) { + (layout == HR_RLQ_RAID5_NR || layout == HR_RLQ_RAID5_NC)) { p_extent = (vol->extent_no - 1) - (stripe / (vol->extent_no - 1)) % vol->extent_no; } else { @@ -555,17 +555,17 @@ static errno_t hr_raid5_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, } uint64_t extent; - if (level == HR_LVL_4 && RLQ == HR_RLQ_RAID4_0) { + if (level == HR_LVL_4 && layout == HR_RLQ_RAID4_0) { extent = (stripe % (vol->extent_no - 1)) + 1; - } else if (level == HR_LVL_4 && RLQ == HR_RLQ_RAID4_N) { + } else if (level == HR_LVL_4 && layout == HR_RLQ_RAID4_N) { extent = stripe % (vol->extent_no - 1); } else if (level == HR_LVL_5 && - (RLQ == HR_RLQ_RAID5_0R || RLQ == HR_RLQ_RAID5_NR)) { + (layout == HR_RLQ_RAID5_0R || layout == HR_RLQ_RAID5_NR)) { if ((stripe % (vol->extent_no - 1)) < p_extent) extent = stripe % (vol->extent_no - 1); else extent = (stripe % (vol->extent_no - 1)) + 1; - } else if (level == HR_LVL_5 && RLQ == HR_RLQ_RAID5_NC) { + } else if (level == HR_LVL_5 && layout == HR_RLQ_RAID5_NC) { extent = ((stripe % (vol->extent_no - 1)) + p_extent + 1) % vol->extent_no; } else { return EINVAL; @@ -653,25 +653,25 @@ static errno_t hr_raid5_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, ext_stripe = stripe / (vol->extent_no - 1); /* stripe level */ - if (level == HR_LVL_5 && RLQ == HR_RLQ_RAID5_0R) { + if (level == HR_LVL_5 && layout == HR_RLQ_RAID5_0R) { p_extent = (stripe / (vol->extent_no - 1)) % vol->extent_no; } else if (level == HR_LVL_5 && - (RLQ == HR_RLQ_RAID5_NR || RLQ == HR_RLQ_RAID5_NC)) { + (layout == HR_RLQ_RAID5_NR || layout == HR_RLQ_RAID5_NC)) { p_extent = (vol->extent_no - 1) - (stripe / (vol->extent_no - 1)) % vol->extent_no; } - if (level == HR_LVL_4 && RLQ == HR_RLQ_RAID4_0) { + if (level == HR_LVL_4 && layout == HR_RLQ_RAID4_0) { extent = (stripe % (vol->extent_no - 1)) + 1; - } else if (level == HR_LVL_4 && RLQ == HR_RLQ_RAID4_N) { + } else if (level == HR_LVL_4 && layout == HR_RLQ_RAID4_N) { extent = stripe % (vol->extent_no - 1); } else if (level == HR_LVL_5 && - (RLQ == HR_RLQ_RAID5_0R || RLQ == HR_RLQ_RAID5_NR)) { + (layout == HR_RLQ_RAID5_0R || layout == HR_RLQ_RAID5_NR)) { if ((stripe % (vol->extent_no - 1)) < p_extent) extent = stripe % (vol->extent_no - 1); else extent = (stripe % (vol->extent_no - 1)) + 1; - } else if (level == HR_LVL_5 && RLQ == HR_RLQ_RAID5_NC) { + } else if (level == HR_LVL_5 && layout == HR_RLQ_RAID5_NC) { extent = ((stripe % (vol->extent_no - 1)) + p_extent + 1) % vol->extent_no; } } diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index 846dc331c9..437e43e139 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -156,7 +156,7 @@ static errno_t hr_fill_meta_from_vol(hr_volume_t *vol, hr_metadata_t *metadata) metadata->extent_no = host2uint32_t_le(vol->extent_no); /* index filled separately for each extent */ metadata->level = host2uint32_t_le(vol->level); - metadata->layout = host2uint32_t_le(vol->RLQ); + metadata->layout = host2uint32_t_le(vol->layout); metadata->strip_size = host2uint32_t_le(vol->strip_size); metadata->nblocks = host2uint64_t_le(vol->nblocks); metadata->data_blkno = host2uint64_t_le(vol->data_blkno); @@ -236,7 +236,7 @@ errno_t hr_fill_vol_from_meta(hr_volume_t *vol) /* TODO: handle version */ vol->level = uint32_t_le2host(metadata->level); - vol->RLQ = (uint8_t)uint32_t_le2host(metadata->layout); + vol->layout = (uint8_t)uint32_t_le2host(metadata->layout); vol->strip_size = uint32_t_le2host(metadata->strip_size); vol->nblocks = uint64_t_le2host(metadata->nblocks); vol->data_blkno = uint64_t_le2host(metadata->data_blkno); diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index 5ef720e457..10239b2f02 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -84,7 +84,7 @@ typedef struct hr_volume { service_id_t svc_id; hr_vol_status_t status; hr_level_t level; - uint8_t RLQ; /* RAID Level Qualifier */ + uint8_t layout; /* RAID Level Qualifier */ char devname[HR_DEVNAME_LEN]; } hr_volume_t; From 8137d36afa1b64e85baf16df4ed9f12468800282 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 23 Dec 2024 13:00:16 +0100 Subject: [PATCH 103/324] hr: fge: style --- uspace/srv/bd/hr/fge.c | 59 +++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/uspace/srv/bd/hr/fge.c b/uspace/srv/bd/hr/fge.c index bc0011c9ef..7f2339dbed 100644 --- a/uspace/srv/bd/hr/fge.c +++ b/uspace/srv/bd/hr/fge.c @@ -58,6 +58,7 @@ struct wu_queue; typedef struct wu_queue wu_queue_t; static void *hr_fpool_make_storage(hr_fpool_t *, ssize_t *); +static void hr_fpool_group_epilogue(hr_fpool_t *); static errno_t fge_fibril(void *); static errno_t wu_queue_init(wu_queue_t *, size_t); static void wu_queue_push(wu_queue_t *, fge_fibril_data_t *); @@ -182,22 +183,6 @@ void hr_fpool_destroy(hr_fpool_t *pool) free(pool); } -static void *hr_fpool_make_storage(hr_fpool_t *pool, ssize_t *rmemslot) -{ - fibril_mutex_lock(&pool->lock); - ssize_t memslot = hr_fpool_get_free_slot(pool); - assert(memslot != -1); - - bitmap_set(&pool->bitmap, memslot, 1); - - fibril_mutex_unlock(&pool->lock); - - if (rmemslot) - *rmemslot = memslot; - - return pool->wu_storage + pool->wu_size * memslot; -} - hr_fgroup_t *hr_fgroup_create(hr_fpool_t *parent, size_t wu_cnt) { hr_fgroup_t *result = malloc(sizeof(hr_fgroup_t)); @@ -224,10 +209,10 @@ hr_fgroup_t *hr_fgroup_create(hr_fpool_t *parent, size_t wu_cnt) */ size_t taking = parent->wu_storage_free_count; result->own_mem = malloc(parent->wu_size * (wu_cnt - taking)); - result->reserved_cnt = taking; - parent->wu_storage_free_count = 0; if (result->own_mem == NULL) goto bad; + result->reserved_cnt = taking; + parent->wu_storage_free_count = 0; } if (result->reserved_cnt > 0) { @@ -312,17 +297,6 @@ void hr_fgroup_submit(hr_fgroup_t *group, hr_wu_t wu, void *arg) wu_queue_push(&group->pool->queue, &executor); } -static void hr_fpool_group_epilogue(hr_fpool_t *pool) -{ - fibril_mutex_lock(&pool->lock); - - pool->active_groups--; - if (pool->active_groups == 0) - fibril_condvar_signal(&pool->all_wus_done); - - fibril_mutex_unlock(&pool->lock); -} - errno_t hr_fgroup_wait(hr_fgroup_t *group, size_t *rokay, size_t *rfailed) { fibril_mutex_lock(&group->lock); @@ -356,6 +330,33 @@ errno_t hr_fgroup_wait(hr_fgroup_t *group, size_t *rokay, size_t *rfailed) return rc; } +static void *hr_fpool_make_storage(hr_fpool_t *pool, ssize_t *rmemslot) +{ + fibril_mutex_lock(&pool->lock); + ssize_t memslot = hr_fpool_get_free_slot(pool); + assert(memslot != -1); + + bitmap_set(&pool->bitmap, memslot, 1); + + fibril_mutex_unlock(&pool->lock); + + if (rmemslot) + *rmemslot = memslot; + + return pool->wu_storage + pool->wu_size * memslot; +} + +static void hr_fpool_group_epilogue(hr_fpool_t *pool) +{ + fibril_mutex_lock(&pool->lock); + + pool->active_groups--; + if (pool->active_groups == 0) + fibril_condvar_signal(&pool->all_wus_done); + + fibril_mutex_unlock(&pool->lock); +} + static errno_t fge_fibril(void *arg) { hr_fpool_t *pool = arg; From eb31781ee320c40a64471040c54c70a2542e9ddd Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 24 Dec 2024 11:43:00 +0100 Subject: [PATCH 104/324] hr: raid5.c: cstyle --- uspace/srv/bd/hr/raid5.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 4f6f233911..7b22322470 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -566,7 +566,9 @@ static errno_t hr_raid5_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, else extent = (stripe % (vol->extent_no - 1)) + 1; } else if (level == HR_LVL_5 && layout == HR_RLQ_RAID5_NC) { - extent = ((stripe % (vol->extent_no - 1)) + p_extent + 1) % vol->extent_no; + extent = + ((stripe % (vol->extent_no - 1)) + p_extent + 1) % + vol->extent_no; } else { return EINVAL; } @@ -654,7 +656,8 @@ static errno_t hr_raid5_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, ext_stripe = stripe / (vol->extent_no - 1); /* stripe level */ if (level == HR_LVL_5 && layout == HR_RLQ_RAID5_0R) { - p_extent = (stripe / (vol->extent_no - 1)) % vol->extent_no; + p_extent = + (stripe / (vol->extent_no - 1)) % vol->extent_no; } else if (level == HR_LVL_5 && (layout == HR_RLQ_RAID5_NR || layout == HR_RLQ_RAID5_NC)) { p_extent = (vol->extent_no - 1) - @@ -672,7 +675,9 @@ static errno_t hr_raid5_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, else extent = (stripe % (vol->extent_no - 1)) + 1; } else if (level == HR_LVL_5 && layout == HR_RLQ_RAID5_NC) { - extent = ((stripe % (vol->extent_no - 1)) + p_extent + 1) % vol->extent_no; + extent = + ((stripe % (vol->extent_no - 1)) + p_extent + 1) % + vol->extent_no; } } From 5a8f69e75ee4d57ab2d6f1d639df7a292110ec01 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Wed, 25 Dec 2024 12:56:55 +0100 Subject: [PATCH 105/324] hr: fge: cstyle --- uspace/srv/bd/hr/fge.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/uspace/srv/bd/hr/fge.c b/uspace/srv/bd/hr/fge.c index 7f2339dbed..230ab0f1be 100644 --- a/uspace/srv/bd/hr/fge.c +++ b/uspace/srv/bd/hr/fge.c @@ -154,13 +154,13 @@ hr_fpool_t *hr_fpool_create(size_t fibril_cnt, size_t max_wus, return result; bad: - if (result->queue.fexecs) + if (result->queue.fexecs != NULL) free(result->queue.fexecs); - if (bitmap_data) + if (bitmap_data != NULL) free(bitmap_data); - if (result->wu_storage) + if (result->wu_storage != NULL) free(result->wu_storage); - if (result->fibrils) + if (result->fibrils != NULL) free(result->fibrils); free(result); @@ -244,9 +244,9 @@ hr_fgroup_t *hr_fgroup_create(hr_fpool_t *parent, size_t wu_cnt) parent->wu_storage_free_count += result->reserved_cnt; fibril_mutex_unlock(&parent->lock); - if (result->memslots) + if (result->memslots != NULL) free(result->memslots); - if (result->own_mem) + if (result->own_mem != NULL) free(result->own_mem); free(result); @@ -321,9 +321,9 @@ errno_t hr_fgroup_wait(hr_fgroup_t *group, size_t *rokay, size_t *rfailed) hr_fpool_group_epilogue(group->pool); - if (group->memslots) + if (group->memslots != NULL) free(group->memslots); - if (group->own_mem) + if (group->own_mem != NULL) free(group->own_mem); free(group); From 08c98d4c9f1194f242500304580ae028b08fb0c9 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Wed, 25 Dec 2024 13:10:53 +0100 Subject: [PATCH 106/324] hr: fge: fix deadlock --- uspace/srv/bd/hr/fge.c | 1 - 1 file changed, 1 deletion(-) diff --git a/uspace/srv/bd/hr/fge.c b/uspace/srv/bd/hr/fge.c index 230ab0f1be..147a575900 100644 --- a/uspace/srv/bd/hr/fge.c +++ b/uspace/srv/bd/hr/fge.c @@ -240,7 +240,6 @@ hr_fgroup_t *hr_fgroup_create(hr_fpool_t *parent, size_t wu_cnt) return result; bad: - fibril_mutex_lock(&parent->lock); parent->wu_storage_free_count += result->reserved_cnt; fibril_mutex_unlock(&parent->lock); From 083ce3373c724b1b122c23ca81d25750922569c4 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Wed, 25 Dec 2024 13:11:25 +0100 Subject: [PATCH 107/324] hr: fge: hr_fpool_create(): assert max_wus > 0 --- uspace/srv/bd/hr/fge.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/uspace/srv/bd/hr/fge.c b/uspace/srv/bd/hr/fge.c index 147a575900..11c9d496d5 100644 --- a/uspace/srv/bd/hr/fge.c +++ b/uspace/srv/bd/hr/fge.c @@ -115,6 +115,8 @@ struct hr_fgroup { hr_fpool_t *hr_fpool_create(size_t fibril_cnt, size_t max_wus, size_t wu_storage_size) { + assert(max_wus > 0 && wu_storage_size > 0); + void *bitmap_data = NULL; hr_fpool_t *result = calloc(1, sizeof(hr_fpool_t)); From 5ee5f670536520c30820ddd6c0085d559657991b Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sat, 28 Dec 2024 20:52:30 +0100 Subject: [PATCH 108/324] hr: fge: make finished_{okay,failed} not atomic And test if all workers finished against submitted rather than started workers count, thus remove hr_fgroup_t.wus_started. --- uspace/srv/bd/hr/fge.c | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/uspace/srv/bd/hr/fge.c b/uspace/srv/bd/hr/fge.c index 11c9d496d5..42c9bf2481 100644 --- a/uspace/srv/bd/hr/fge.c +++ b/uspace/srv/bd/hr/fge.c @@ -105,9 +105,8 @@ struct hr_fgroup { void *own_mem; size_t own_used; errno_t final_errno; - atomic_size_t finished_okay; - atomic_size_t finished_fail; - atomic_size_t wus_started; + size_t finished_okay; + size_t finished_fail; fibril_mutex_t lock; fibril_condvar_t all_done; }; @@ -234,7 +233,6 @@ hr_fgroup_t *hr_fgroup_create(hr_fpool_t *parent, size_t wu_cnt) result->final_errno = EOK; result->finished_okay = 0; result->finished_fail = 0; - result->wus_started = 0; fibril_mutex_initialize(&result->lock); fibril_condvar_initialize(&result->all_done); @@ -280,7 +278,7 @@ void *hr_fgroup_alloc(hr_fgroup_t *group) void hr_fgroup_submit(hr_fgroup_t *group, hr_wu_t wu, void *arg) { fibril_mutex_lock(&group->lock); - assert(group->submitted + 1 <= group->wu_cnt); + assert(group->submitted < group->wu_cnt); fge_fibril_data_t executor; executor.wu = wu; @@ -300,10 +298,12 @@ void hr_fgroup_submit(hr_fgroup_t *group, hr_wu_t wu, void *arg) errno_t hr_fgroup_wait(hr_fgroup_t *group, size_t *rokay, size_t *rfailed) { + assert(group->submitted == group->wu_cnt); + fibril_mutex_lock(&group->lock); while (true) { size_t finished = group->finished_fail + group->finished_okay; - if (group->wus_started != 0 && group->wus_started == finished) + if (group->wu_cnt == finished) break; fibril_condvar_wait(&group->all_done, &group->lock); @@ -315,7 +315,7 @@ errno_t hr_fgroup_wait(hr_fgroup_t *group, size_t *rokay, size_t *rfailed) *rfailed = group->finished_fail; errno_t rc = EOK; - if (group->finished_okay != group->wus_started) + if (group->finished_okay != group->wu_cnt) rc = EIO; fibril_mutex_unlock(&group->lock); @@ -381,17 +381,17 @@ static errno_t fge_fibril(void *arg) hr_fgroup_t *group = executor.group; - atomic_fetch_add_explicit(&group->wus_started, 1, - memory_order_relaxed); - errno_t rc = executor.wu(executor.arg); - if (rc == EOK) - atomic_fetch_add_explicit(&group->finished_okay, 1, - memory_order_relaxed); - else - atomic_fetch_add_explicit(&group->finished_fail, 1, - memory_order_relaxed); + if (rc == EOK) { + fibril_mutex_lock(&group->lock); + group->finished_okay++; + fibril_mutex_unlock(&group->lock); + } else { + fibril_mutex_lock(&group->lock); + group->finished_fail++; + fibril_mutex_unlock(&group->lock); + } fibril_mutex_lock(&pool->lock); if (executor.memslot > -1) { @@ -399,9 +399,10 @@ static errno_t fge_fibril(void *arg) pool->wu_storage_free_count++; } - size_t group_total_done = group->finished_fail + - group->finished_okay; - if (group->wus_started == group_total_done) + fibril_mutex_lock(&group->lock); + size_t finished = group->finished_fail + group->finished_okay; + fibril_mutex_unlock(&group->lock); + if (finished == group->wu_cnt) fibril_condvar_signal(&group->all_done); fibril_mutex_unlock(&pool->lock); From 723f1d98e99f4824a68ba99c63a1f32280726650 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sat, 28 Dec 2024 21:09:30 +0100 Subject: [PATCH 109/324] hr: fge: fgroup_create(): assert worker count > 0 --- uspace/srv/bd/hr/fge.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/uspace/srv/bd/hr/fge.c b/uspace/srv/bd/hr/fge.c index 42c9bf2481..62c33e6241 100644 --- a/uspace/srv/bd/hr/fge.c +++ b/uspace/srv/bd/hr/fge.c @@ -186,6 +186,8 @@ void hr_fpool_destroy(hr_fpool_t *pool) hr_fgroup_t *hr_fgroup_create(hr_fpool_t *parent, size_t wu_cnt) { + assert(wu_cnt > 0); + hr_fgroup_t *result = malloc(sizeof(hr_fgroup_t)); if (result == NULL) return NULL; From 7a3529a8736f62cf391c3de6400272e1324a36fc Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sat, 28 Dec 2024 21:31:24 +0100 Subject: [PATCH 110/324] hr: util.c: bounds check on state updates --- uspace/srv/bd/hr/util.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 3c87d113e6..766d64d4cf 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -212,6 +212,8 @@ void hr_add_ba_offset(hr_volume_t *vol, uint64_t *ba) void hr_update_ext_status(hr_volume_t *vol, size_t extent, hr_ext_status_t s) { + assert(extent < vol->extent_no); + hr_ext_status_t old = vol->extents[extent].status; HR_WARN("\"%s\": changing extent %lu state: %s -> %s\n", vol->devname, extent, hr_get_ext_status_msg(old), @@ -221,6 +223,8 @@ void hr_update_ext_status(hr_volume_t *vol, size_t extent, hr_ext_status_t s) void hr_update_hotspare_status(hr_volume_t *vol, size_t hs, hr_ext_status_t s) { + assert(hs < vol->hotspare_no); + hr_ext_status_t old = vol->hotspares[hs].status; HR_WARN("\"%s\": changing hotspare %lu state: %s -> %s\n", vol->devname, hs, hr_get_ext_status_msg(old), From 685c0ab48ca177c94c53a8bda6aab27c491bbac4 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 30 Dec 2024 23:28:13 +0100 Subject: [PATCH 111/324] hr: superblock.c: style --- uspace/srv/bd/hr/superblock.c | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index 437e43e139..e5a93b6c65 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -51,6 +51,7 @@ static errno_t read_metadata(service_id_t, hr_metadata_t *); static errno_t hr_fill_meta_from_vol(hr_volume_t *, hr_metadata_t *); +static errno_t validate_meta(hr_metadata_t *); errno_t hr_write_meta_to_vol(hr_volume_t *vol) { @@ -133,9 +134,8 @@ static errno_t hr_fill_meta_from_vol(hr_volume_t *vol, hr_metadata_t *metadata) { HR_DEBUG("hr_fill_meta_from_vol()\n"); - size_t meta_blkno; /* blocks needed to write metadata */ + size_t meta_blkno = HR_META_OFF + HR_META_SIZE; - meta_blkno = (HR_META_OFF + HR_META_SIZE); if (vol->level != HR_LVL_1) meta_blkno *= vol->extent_no; @@ -188,23 +188,24 @@ errno_t hr_fill_vol_from_meta(hr_volume_t *vol) if (metadata == NULL) return ENOMEM; - service_id_t cfg_svc_id_order[HR_MAX_EXTENTS] = { 0 }; + service_id_t assembly_svc_id_order[HR_MAX_EXTENTS] = { 0 }; for (size_t i = 0; i < vol->extent_no; i++) - cfg_svc_id_order[i] = vol->extents[i].svc_id; + assembly_svc_id_order[i] = vol->extents[i].svc_id; - int32_t md_order[HR_MAX_EXTENTS] = { 0 }; + size_t md_order_indices[HR_MAX_EXTENTS] = { 0 }; for (size_t i = 0; i < vol->extent_no; i++) { - if (cfg_svc_id_order[i] == 0) { - md_order[i] = -1; + if (assembly_svc_id_order[i] == 0) { + /* set invalid index */ + md_order_indices[i] = vol->extent_no; continue; } - rc = read_metadata(cfg_svc_id_order[i], metadata); + rc = read_metadata(assembly_svc_id_order[i], metadata); if (rc != EOK) goto end; rc = validate_meta(metadata); if (rc != EOK) goto end; - md_order[i] = uint32_t_le2host(metadata->index); + md_order_indices[i] = uint32_t_le2host(metadata->index); } for (size_t i = 0; i < vol->extent_no; i++) { @@ -215,8 +216,9 @@ errno_t hr_fill_vol_from_meta(hr_volume_t *vol) /* sort */ for (size_t i = 0; i < vol->extent_no; i++) { for (size_t j = 0; j < vol->extent_no; j++) { - if (i == (uint32_t)md_order[j]) { - vol->extents[i].svc_id = cfg_svc_id_order[j]; + if (i == md_order_indices[j]) { + vol->extents[i].svc_id = + assembly_svc_id_order[j]; vol->extents[i].status = HR_EXT_ONLINE; } } @@ -255,18 +257,13 @@ errno_t hr_fill_vol_from_meta(hr_volume_t *vol) static errno_t read_metadata(service_id_t dev, hr_metadata_t *metadata) { errno_t rc; - size_t bsize; uint64_t nblocks; - rc = block_get_bsize(dev, &bsize); - if (rc != EOK) - return rc; - rc = block_get_nblocks(dev, &nblocks); if (rc != EOK) return rc; - if (nblocks < (HR_META_SIZE + HR_META_OFF) * bsize) + if (nblocks < HR_META_SIZE + HR_META_OFF) return EINVAL; rc = block_read_direct(dev, HR_META_OFF, HR_META_SIZE, metadata); From 7d2527377108002db9460fa9aca3c771f07238a6 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 31 Dec 2024 00:07:35 +0100 Subject: [PATCH 112/324] hrctl: initialize hr session struct --- uspace/app/hrctl/hrctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index ad092d8125..9ab87669b8 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -231,7 +231,7 @@ int main(int argc, char **argv) int retval, c; bool create, assemble; long fail_extent = -1; - hr_t *hr; + hr_t *hr = NULL; hr_config_t *cfg; cfg = calloc(1, sizeof(hr_config_t)); From 40be7eb4cdef8c2565a90c877426276916ce26f1 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 31 Dec 2024 00:07:56 +0100 Subject: [PATCH 113/324] lib/device/src/hr.c: session init style --- uspace/lib/device/src/hr.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index 921dec838b..999ebb9f17 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -46,8 +46,12 @@ errno_t hr_sess_init(hr_t **rhr) { errno_t rc; + hr_t *hr = NULL; - hr_t *hr = calloc(1, sizeof(hr_t)); + if (rhr == NULL) + return EINVAL; + + hr = calloc(1, sizeof(hr_t)); if (hr == NULL) { rc = ENOMEM; goto error; @@ -56,10 +60,8 @@ errno_t hr_sess_init(hr_t **rhr) service_id_t hr_svcid; rc = loc_service_get_id(SERVICE_NAME_HR, &hr_svcid, 0); - if (rc != EOK) { - rc = EIO; + if (rc != EOK) goto error; - } hr->sess = loc_service_connect(hr_svcid, INTERFACE_HR, 0); if (hr->sess == NULL) { @@ -72,7 +74,7 @@ errno_t hr_sess_init(hr_t **rhr) error: if (hr != NULL) free(hr); - *rhr = NULL; + return rc; } From bc3d695b6287b7807d133734f5b8790bdcb16cb4 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 5 Jan 2025 19:22:28 +0100 Subject: [PATCH 114/324] hr: RAID0 parallelization --- uspace/srv/bd/hr/hr.c | 23 +++++- uspace/srv/bd/hr/io.c | 84 ++++++++++++++++++++ uspace/srv/bd/hr/io.h | 57 +++++++++++++ uspace/srv/bd/hr/meson.build | 3 +- uspace/srv/bd/hr/raid0.c | 150 ++++++++++++++++++++--------------- uspace/srv/bd/hr/util.h | 3 +- uspace/srv/bd/hr/var.h | 43 +++++++--- 7 files changed, 283 insertions(+), 80 deletions(-) create mode 100644 uspace/srv/bd/hr/io.c create mode 100644 uspace/srv/bd/hr/io.h diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index f6e395c148..312f623728 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Miroslav Cimerman + * Copyright (c) 2025 Miroslav Cimerman * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -48,6 +48,8 @@ #include #include +#include "fge.h" +#include "io.h" #include "superblock.h" #include "util.h" #include "var.h" @@ -82,6 +84,7 @@ static errno_t hr_remove_volume(service_id_t svc_id) fibril_mutex_lock(&hr_volumes_lock); list_foreach(hr_volumes, lvolumes, hr_volume_t, vol) { if (vol->svc_id == svc_id) { + hr_fpool_destroy(vol->fge); hr_fini_devs(vol); list_remove(&vol->lvolumes); free(vol); @@ -154,6 +157,15 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) return; } + hr_fpool_t *fge = hr_fpool_create(16, 32, sizeof(hr_io_t)); + if (fge == NULL) { + free(new_volume); + free(cfg); + async_answer_0(icall, ENOMEM); + return; + } + new_volume->fge = fge; + str_cpy(new_volume->devname, HR_DEVNAME_LEN, cfg->devname); for (i = 0; i < cfg->dev_no; i++) new_volume->extents[i].svc_id = cfg->devs[i]; @@ -233,7 +245,13 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) goto error; } - fibril_mutex_initialize(&new_volume->lock); + fibril_mutex_initialize(&new_volume->lock); /* XXX: will remove this */ + + fibril_mutex_initialize(&new_volume->halt_lock); + new_volume->halt_please = false; + + fibril_rwlock_initialize(&new_volume->extents_lock); + fibril_rwlock_initialize(&new_volume->states_lock); list_initialize(&new_volume->range_lock_list); fibril_mutex_initialize(&new_volume->range_lock_list_lock); @@ -259,6 +277,7 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) return; error: free(cfg); + free(fge); hr_fini_devs(new_volume); free(new_volume); async_answer_0(icall, rc); diff --git a/uspace/srv/bd/hr/io.c b/uspace/srv/bd/hr/io.c new file mode 100644 index 0000000000..5e7fb4f2de --- /dev/null +++ b/uspace/srv/bd/hr/io.c @@ -0,0 +1,84 @@ +/* + * 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 "io.h" +#include "util.h" +#include "var.h" + +errno_t hr_io_worker(void *arg) +{ + hr_io_t *io = arg; + hr_extent_t *extents = (hr_extent_t *)&io->vol->extents; + size_t ext_idx = io->extent; + errno_t rc; + + HR_DEBUG("WORKER on extent: %lu, ba: %lu, cnt: %lu\n", + io->extent, io->ba, io->cnt); + + switch (io->type) { + case HR_BD_SYNC: + rc = block_sync_cache(extents[ext_idx].svc_id, + io->ba, io->cnt); + if (rc == ENOTSUP) + rc = EOK; + break; + case HR_BD_READ: + rc = block_read_direct(extents[ext_idx].svc_id, io->ba, + io->cnt, io->data_read); + break; + case HR_BD_WRITE: + rc = block_write_direct(extents[ext_idx].svc_id, io->ba, + io->cnt, io->data_write); + break; + default: + return EINVAL; + } + + if (rc != EOK) + io->state_callback(io->vol, io->extent, rc); + + HR_DEBUG("WORKER rc: %s\n", str_error(rc)); + + return rc; +} + +/** @} + */ diff --git a/uspace/srv/bd/hr/io.h b/uspace/srv/bd/hr/io.h new file mode 100644 index 0000000000..fc45478071 --- /dev/null +++ b/uspace/srv/bd/hr/io.h @@ -0,0 +1,57 @@ +/* + * 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 + */ + +#ifndef _HR_IO_H +#define _HR_IO_H + +#include "var.h" + +typedef struct hr_io { + hr_bd_op_type_t type; + uint64_t ba; + uint64_t cnt; + size_t extent; + void *data_read; + const void *data_write; + hr_volume_t *vol; + void (*state_callback)(hr_volume_t *, size_t, errno_t); +} hr_io_t; + +errno_t hr_io_worker(void *); + +#endif + +/** @} + */ diff --git a/uspace/srv/bd/hr/meson.build b/uspace/srv/bd/hr/meson.build index 34f26af681..4b3a319187 100644 --- a/uspace/srv/bd/hr/meson.build +++ b/uspace/srv/bd/hr/meson.build @@ -1,5 +1,5 @@ # -# Copyright (c) 2024 Miroslav Cimerman +# Copyright (c) 2025 Miroslav Cimerman # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -30,6 +30,7 @@ deps = [ 'block', 'device' ] src = files( 'fge.c', 'hr.c', + 'io.c', 'raid0.c', 'raid1.c', 'raid5.c', diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index 6aa3709870..f2a7aa801d 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Miroslav Cimerman + * Copyright (c) 2025 Miroslav Cimerman * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -47,13 +47,13 @@ #include #include +#include "io.h" #include "superblock.h" #include "util.h" #include "var.h" extern loc_srv_t *hr_srv; -static errno_t hr_raid0_check_vol_status(hr_volume_t *); static errno_t hr_raid0_update_vol_status(hr_volume_t *); static errno_t hr_raid0_bd_op(hr_bd_op_type_t, bd_srv_t *, aoff64_t, size_t, void *, const void *, size_t); @@ -94,6 +94,8 @@ errno_t hr_raid0_create(hr_volume_t *new_volume) if (rc != EOK) return rc; + hr_update_vol_status(new_volume, HR_VOL_ONLINE); + bd_srvs_init(&new_volume->hr_bds); new_volume->hr_bds.ops = &hr_raid0_bd_ops; new_volume->hr_bds.sarg = new_volume; @@ -126,9 +128,7 @@ errno_t hr_raid0_init(hr_volume_t *vol) void hr_raid0_status_event(hr_volume_t *vol) { - fibril_mutex_lock(&vol->lock); (void)hr_raid0_update_vol_status(vol); - fibril_mutex_unlock(&vol->lock); } static errno_t hr_raid0_bd_open(bd_srvs_t *bds, bd_srv_t *bd) @@ -176,35 +176,50 @@ static errno_t hr_raid0_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb) return EOK; } -static errno_t hr_raid0_check_vol_status(hr_volume_t *vol) -{ - if (vol->status == HR_VOL_ONLINE) - return EOK; - return EIO; -} - /* * Update vol->status and return EOK if volume * is usable */ static errno_t hr_raid0_update_vol_status(hr_volume_t *vol) { + fibril_rwlock_read_lock(&vol->states_lock); hr_vol_status_t old_state = vol->status; for (size_t i = 0; i < vol->extent_no; i++) { if (vol->extents[i].status != HR_EXT_ONLINE) { + fibril_rwlock_read_unlock(&vol->states_lock); + fibril_rwlock_write_lock(&vol->states_lock); if (old_state != HR_VOL_FAULTY) hr_update_vol_status(vol, HR_VOL_FAULTY); + fibril_rwlock_write_unlock(&vol->states_lock); return EIO; } } - - if (old_state != HR_VOL_ONLINE) - hr_update_vol_status(vol, HR_VOL_ONLINE); + fibril_rwlock_read_unlock(&vol->states_lock); return EOK; } +static void raid0_state_callback(hr_volume_t *vol, size_t extent, errno_t rc) +{ + if (rc == EOK) + return; + + fibril_rwlock_write_lock(&vol->states_lock); + + switch (rc) { + case ENOENT: + hr_update_ext_status(vol, extent, HR_EXT_MISSING); + break; + default: + hr_update_ext_status(vol, extent, HR_EXT_FAILED); + } + + hr_update_vol_status(vol, HR_VOL_FAULTY); + + fibril_rwlock_write_unlock(&vol->states_lock); +} + static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, size_t cnt, void *dst, const void *src, size_t size) { @@ -215,11 +230,34 @@ static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, const uint8_t *data_write = src; uint8_t *data_read = dst; + fibril_rwlock_read_lock(&vol->states_lock); + if (vol->status != HR_VOL_ONLINE) { + fibril_rwlock_read_unlock(&vol->states_lock); + return EIO; + } + fibril_rwlock_read_unlock(&vol->states_lock); + /* propagate sync */ if (type == HR_BD_SYNC && ba == 0 && cnt == 0) { - hr_sync_all_extents(vol); - rc = hr_raid0_update_vol_status(vol); - return rc; + hr_fgroup_t *group = hr_fgroup_create(vol->fge, vol->extent_no); + + for (size_t i = 0; i < vol->extent_no; i++) { + hr_io_t *io = hr_fgroup_alloc(group); + io->extent = i; + io->ba = ba; + io->cnt = cnt; + io->type = type; + io->vol = vol; + io->state_callback = raid0_state_callback; + + hr_fgroup_submit(group, hr_io_worker, io); + } + + size_t bad; + (void)hr_fgroup_wait(group, NULL, &bad); + if (bad > 0) + return EIO; + return EOK; } if (type == HR_BD_READ || type == HR_BD_WRITE) @@ -231,71 +269,57 @@ static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, return rc; uint64_t strip_size = vol->strip_size / vol->bsize; /* in blocks */ - uint64_t stripe = ba / strip_size; /* stripe number */ - uint64_t extent = stripe % vol->extent_no; - uint64_t ext_stripe = stripe / vol->extent_no; /* stripe level */ - uint64_t strip_off = ba % strip_size; /* strip offset */ + uint64_t strip_no = ba / strip_size; + uint64_t extent = strip_no % vol->extent_no; + uint64_t stripe = strip_no / vol->extent_no; + uint64_t strip_off = ba % strip_size; - fibril_mutex_lock(&vol->lock); + left = cnt; - rc = hr_raid0_check_vol_status(vol); - if (rc != EOK) { - fibril_mutex_unlock(&vol->lock); - return EIO; - } + /* calculate how many strips does the IO span */ + size_t end_strip_no = (ba + cnt - 1) / strip_size; + size_t span = end_strip_no - strip_no + 1; - left = cnt; + hr_fgroup_t *group = hr_fgroup_create(vol->fge, span); while (left != 0) { - phys_block = ext_stripe * strip_size + strip_off; + phys_block = stripe * strip_size + strip_off; cnt = min(left, strip_size - strip_off); len = vol->bsize * cnt; hr_add_ba_offset(vol, &phys_block); - switch (type) { - case HR_BD_SYNC: - rc = block_sync_cache(vol->extents[extent].svc_id, - phys_block, cnt); - /* allow unsupported sync */ - if (rc == ENOTSUP) - rc = EOK; - break; - case HR_BD_READ: - rc = block_read_direct(vol->extents[extent].svc_id, - phys_block, cnt, data_read); + + hr_io_t *io = hr_fgroup_alloc(group); + io->extent = extent; + io->data_write = data_write; + io->data_read = data_read; + io->ba = ba; + io->cnt = cnt; + io->type = type; + io->vol = vol; + io->state_callback = raid0_state_callback; + + hr_fgroup_submit(group, hr_io_worker, io); + + if (type == HR_BD_READ) data_read += len; - break; - case HR_BD_WRITE: - rc = block_write_direct(vol->extents[extent].svc_id, - phys_block, cnt, data_write); + else if (type == HR_BD_WRITE) data_write += len; - break; - default: - rc = EINVAL; - } - - if (rc == ENOENT) { - hr_update_ext_status(vol, extent, HR_EXT_MISSING); - rc = EIO; - goto error; - } else if (rc != EOK) { - hr_update_ext_status(vol, extent, HR_EXT_FAILED); - rc = EIO; - goto error; - } left -= cnt; strip_off = 0; extent++; if (extent >= vol->extent_no) { - ext_stripe++; + stripe++; extent = 0; } } -error: - (void)hr_raid0_update_vol_status(vol); - fibril_mutex_unlock(&vol->lock); - return rc; + size_t bad; + (void)hr_fgroup_wait(group, NULL, &bad); + if (bad > 0) + return EIO; + + return EOK; } /** @} diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index 352f68d91c..59f59e7e30 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Miroslav Cimerman + * Copyright (c) 2025 Miroslav Cimerman * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -37,6 +37,7 @@ #define _HR_UTIL_H #include +#include #include "var.h" diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index 10239b2f02..499af1bbe5 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Miroslav Cimerman + * Copyright (c) 2025 Miroslav Cimerman * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -42,6 +42,8 @@ #include #include +#include "fge.h" + #define NAME "hr" #define HR_STRIP_SIZE DATA_XFER_LIMIT @@ -59,33 +61,48 @@ typedef struct hr_volume { hr_ops_t hr_ops; bd_srvs_t hr_bds; - link_t lvolumes; + link_t lvolumes; /* protected by static hr_volumes_lock in hr.c */ + + /* + * XXX: will be gone after all paralelization, but still used + * in yet-unparallelized levels + */ fibril_mutex_t lock; list_t range_lock_list; fibril_mutex_t range_lock_list_lock; - size_t extent_no; - hr_extent_t extents[HR_MAX_EXTENTS]; - - size_t hotspare_no; - hr_extent_t hotspares[HR_MAX_HOTSPARES]; + hr_fpool_t *fge; + /* after assembly, these are invariant */ + size_t extent_no; size_t bsize; uint64_t nblocks; uint64_t data_blkno; uint64_t data_offset; /* in blocks */ uint32_t strip_size; + hr_level_t level; + uint8_t layout; /* RAID Level Qualifier */ + service_id_t svc_id; + char devname[HR_DEVNAME_LEN]; - uint64_t rebuild_blk; + hr_extent_t extents[HR_MAX_EXTENTS]; + size_t hotspare_no; + hr_extent_t hotspares[HR_MAX_HOTSPARES]; - uint64_t counter; /* metadata syncing */ + /* protects ordering (hr_extent_t.svc_id, hotspares) */ + fibril_rwlock_t extents_lock; - service_id_t svc_id; + /* protects states (hr_extent_t.status, hr_vol_status_t.status) */ + fibril_rwlock_t states_lock; + + /* for halting IO requests when a REBUILD start waits */ + bool halt_please; + fibril_mutex_t halt_lock; + + uint64_t rebuild_blk; + uint64_t counter; /* metadata syncing */ hr_vol_status_t status; - hr_level_t level; - uint8_t layout; /* RAID Level Qualifier */ - char devname[HR_DEVNAME_LEN]; } hr_volume_t; typedef enum { From a5c2960e57bfe2d55583c6cc8ea71ce723ef8ec9 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 12 Jan 2025 16:46:30 +0100 Subject: [PATCH 115/324] hr: RAID0: pass actual block address to workers --- uspace/srv/bd/hr/raid0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index f2a7aa801d..c06ead6aee 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -292,7 +292,7 @@ static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, io->extent = extent; io->data_write = data_write; io->data_read = data_read; - io->ba = ba; + io->ba = phys_block; io->cnt = cnt; io->type = type; io->vol = vol; From efc6259f760f98a3620977ee103110dcd006d8e3 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 12 Jan 2025 16:49:53 +0100 Subject: [PATCH 116/324] hr: fge: aggregate ENOMEM final errno --- uspace/srv/bd/hr/fge.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/uspace/srv/bd/hr/fge.c b/uspace/srv/bd/hr/fge.c index 62c33e6241..0d50686a06 100644 --- a/uspace/srv/bd/hr/fge.c +++ b/uspace/srv/bd/hr/fge.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Miroslav Cimerman + * Copyright (c) 2025 Miroslav Cimerman * Copyright (c) 2024 Vojtech Horky * All rights reserved. * @@ -316,9 +316,7 @@ errno_t hr_fgroup_wait(hr_fgroup_t *group, size_t *rokay, size_t *rfailed) if (rfailed) *rfailed = group->finished_fail; - errno_t rc = EOK; - if (group->finished_okay != group->wu_cnt) - rc = EIO; + errno_t rc = group->final_errno; fibril_mutex_unlock(&group->lock); @@ -392,6 +390,8 @@ static errno_t fge_fibril(void *arg) } else { fibril_mutex_lock(&group->lock); group->finished_fail++; + if (rc == ENOMEM) + group->final_errno = ENOMEM; fibril_mutex_unlock(&group->lock); } From 0d77d309854435760a96149092c5a97c76ab4ec2 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 12 Jan 2025 16:58:35 +0100 Subject: [PATCH 117/324] hr: hr_io_worker(): ENOMEM handling for WRITEs Call state callback on rc == ENOMEM only if the IO is a WRITE. --- uspace/srv/bd/hr/io.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/uspace/srv/bd/hr/io.c b/uspace/srv/bd/hr/io.c index 5e7fb4f2de..9909802c71 100644 --- a/uspace/srv/bd/hr/io.c +++ b/uspace/srv/bd/hr/io.c @@ -72,7 +72,13 @@ errno_t hr_io_worker(void *arg) return EINVAL; } - if (rc != EOK) + /* + * We don't have to invalidate extents who got ENOMEM + * on READ/SYNC. But when we get ENOMEM on a WRITE, we have + * to invalidate it, because there could have been + * other writes, there is no way to rollback. + */ + if (rc != EOK && (rc != ENOMEM || io->type == HR_BD_WRITE)) io->state_callback(io->vol, io->extent, rc); HR_DEBUG("WORKER rc: %s\n", str_error(rc)); From 4660649f6bb5e1677ea38c2a64229885da4f377a Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 12 Jan 2025 17:12:01 +0100 Subject: [PATCH 118/324] hr: RAID0: return ENOMEM on out-of-memory READs --- uspace/srv/bd/hr/raid0.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index c06ead6aee..af50718f93 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -239,7 +239,8 @@ static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, /* propagate sync */ if (type == HR_BD_SYNC && ba == 0 && cnt == 0) { - hr_fgroup_t *group = hr_fgroup_create(vol->fge, vol->extent_no); + hr_fgroup_t *group = hr_fgroup_create(vol->fge, + vol->extent_no); for (size_t i = 0; i < vol->extent_no; i++) { hr_io_t *io = hr_fgroup_alloc(group); @@ -254,9 +255,13 @@ static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, } size_t bad; - (void)hr_fgroup_wait(group, NULL, &bad); + rc = hr_fgroup_wait(group, NULL, &bad); + if (rc == ENOMEM) + return ENOMEM; + if (bad > 0) return EIO; + return EOK; } @@ -315,7 +320,10 @@ static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, } size_t bad; - (void)hr_fgroup_wait(group, NULL, &bad); + rc = hr_fgroup_wait(group, NULL, &bad); + if (rc == ENOMEM && type == HR_BD_READ) + return ENOMEM; + if (bad > 0) return EIO; From ee47537538e95ab104d628adddb006083ec3dedd Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 12 Jan 2025 17:12:38 +0100 Subject: [PATCH 119/324] hr: RAID0: refactor hr_raid0_update_vol_status() --- uspace/srv/bd/hr/raid0.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index af50718f93..265e860660 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -54,7 +54,7 @@ extern loc_srv_t *hr_srv; -static errno_t hr_raid0_update_vol_status(hr_volume_t *); +static void hr_raid0_update_vol_status(hr_volume_t *); static errno_t hr_raid0_bd_op(hr_bd_op_type_t, bd_srv_t *, aoff64_t, size_t, void *, const void *, size_t); @@ -90,11 +90,9 @@ errno_t hr_raid0_create(hr_volume_t *new_volume) return EINVAL; } - rc = hr_raid0_update_vol_status(new_volume); - if (rc != EOK) - return rc; - - hr_update_vol_status(new_volume, HR_VOL_ONLINE); + hr_raid0_update_vol_status(new_volume); + if (new_volume->status != HR_VOL_ONLINE) + return EINVAL; bd_srvs_init(&new_volume->hr_bds); new_volume->hr_bds.ops = &hr_raid0_bd_ops; @@ -128,7 +126,7 @@ errno_t hr_raid0_init(hr_volume_t *vol) void hr_raid0_status_event(hr_volume_t *vol) { - (void)hr_raid0_update_vol_status(vol); + hr_raid0_update_vol_status(vol); } static errno_t hr_raid0_bd_open(bd_srvs_t *bds, bd_srv_t *bd) @@ -176,28 +174,31 @@ static errno_t hr_raid0_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb) return EOK; } -/* - * Update vol->status and return EOK if volume - * is usable - */ -static errno_t hr_raid0_update_vol_status(hr_volume_t *vol) +static void hr_raid0_update_vol_status(hr_volume_t *vol) { fibril_rwlock_read_lock(&vol->states_lock); + hr_vol_status_t old_state = vol->status; for (size_t i = 0; i < vol->extent_no; i++) { if (vol->extents[i].status != HR_EXT_ONLINE) { fibril_rwlock_read_unlock(&vol->states_lock); - fibril_rwlock_write_lock(&vol->states_lock); - if (old_state != HR_VOL_FAULTY) + + if (old_state != HR_VOL_FAULTY) { + fibril_rwlock_write_lock(&vol->states_lock); hr_update_vol_status(vol, HR_VOL_FAULTY); - fibril_rwlock_write_unlock(&vol->states_lock); - return EIO; + fibril_rwlock_write_unlock(&vol->states_lock); + } + return; } } fibril_rwlock_read_unlock(&vol->states_lock); - return EOK; + if (old_state != HR_VOL_ONLINE) { + fibril_rwlock_write_lock(&vol->states_lock); + hr_update_vol_status(vol, HR_VOL_ONLINE); + fibril_rwlock_write_unlock(&vol->states_lock); + } } static void raid0_state_callback(hr_volume_t *vol, size_t extent, errno_t rc) From 58d82fa2798504f981fb5b24f7ed6ed42d2a9651 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 12 Jan 2025 17:49:51 +0100 Subject: [PATCH 120/324] hr: parallelize RAID1 changes in main hr_volume_t struct: - new mutex hotspare_lock for protecting hotspares - rebuild_blk is _Atomic --- uspace/srv/bd/hr/hr.c | 12 +- uspace/srv/bd/hr/raid1.c | 505 +++++++++++++++++++++++++++------------ uspace/srv/bd/hr/var.h | 13 +- 3 files changed, 368 insertions(+), 162 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 312f623728..2687196b02 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -253,9 +254,13 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) fibril_rwlock_initialize(&new_volume->extents_lock); fibril_rwlock_initialize(&new_volume->states_lock); + fibril_mutex_initialize(&new_volume->hotspare_lock); + list_initialize(&new_volume->range_lock_list); fibril_mutex_initialize(&new_volume->range_lock_list_lock); + atomic_init(&new_volume->rebuild_blk, 0); + rc = new_volume->hr_ops.create(new_volume); if (rc != EOK) goto error; @@ -309,10 +314,11 @@ static void hr_stop_srv(ipc_call_t *icall) } rc = loc_service_unregister(hr_srv, svc_id); } else { - /* fibril safe for now */ - fibril_mutex_lock(&vol->lock); + fibril_rwlock_write_lock(&vol->states_lock); + fibril_rwlock_read_lock(&vol->extents_lock); hr_update_ext_status(vol, fail_extent, HR_EXT_FAILED); - fibril_mutex_unlock(&vol->lock); + fibril_rwlock_read_unlock(&vol->extents_lock); + fibril_rwlock_write_unlock(&vol->states_lock); vol->hr_ops.status_event(vol); } diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 387a9cf522..a6ffb61b76 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Miroslav Cimerman + * Copyright (c) 2025 Miroslav Cimerman * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -42,21 +42,27 @@ #include #include #include +#include #include #include #include +#include "fge.h" +#include "io.h" #include "superblock.h" #include "util.h" #include "var.h" extern loc_srv_t *hr_srv; -static errno_t hr_raid1_check_vol_status(hr_volume_t *); -static errno_t hr_raid1_update_vol_status(hr_volume_t *); -static void hr_raid1_handle_extent_error(hr_volume_t *, size_t, errno_t); +static void hr_raid1_update_vol_status(hr_volume_t *); +static void hr_raid1_ext_state_callback(hr_volume_t *, size_t, errno_t); +static size_t hr_raid1_count_good_extents(hr_volume_t *, uint64_t, size_t, + uint64_t); static errno_t hr_raid1_bd_op(hr_bd_op_type_t, bd_srv_t *, aoff64_t, size_t, void *, const void *, size_t); +static errno_t swap_hs(hr_volume_t *, size_t, size_t); +static errno_t init_rebuild(hr_volume_t *, size_t *); static errno_t hr_raid1_rebuild(void *); /* bdops */ @@ -91,14 +97,14 @@ errno_t hr_raid1_create(hr_volume_t *new_volume) return EINVAL; } - rc = hr_raid1_update_vol_status(new_volume); - if (rc != EOK) - return rc; - bd_srvs_init(&new_volume->hr_bds); new_volume->hr_bds.ops = &hr_raid1_bd_ops; new_volume->hr_bds.sarg = new_volume; + hr_raid1_update_vol_status(new_volume); + if (new_volume->status == HR_VOL_FAULTY) + return EINVAL; + rc = hr_register_volume(new_volume); return rc; @@ -127,29 +133,31 @@ errno_t hr_raid1_init(hr_volume_t *vol) void hr_raid1_status_event(hr_volume_t *vol) { - fibril_mutex_lock(&vol->lock); - (void)hr_raid1_update_vol_status(vol); - fibril_mutex_unlock(&vol->lock); + hr_raid1_update_vol_status(vol); } errno_t hr_raid1_add_hotspare(hr_volume_t *vol, service_id_t hotspare) { HR_DEBUG("hr_raid1_add_hotspare()\n"); - fibril_mutex_lock(&vol->lock); + errno_t rc = EOK; + + fibril_mutex_lock(&vol->hotspare_lock); if (vol->hotspare_no >= HR_MAX_HOTSPARES) { HR_ERROR("hr_raid1_add_hotspare(): cannot add more hotspares " "to \"%s\"\n", vol->devname); - fibril_mutex_unlock(&vol->lock); - return ELIMIT; + rc = ELIMIT; + goto error; } - vol->hotspares[vol->hotspare_no].svc_id = hotspare; - hr_update_hotspare_status(vol, vol->hotspare_no, HR_EXT_HOTSPARE); + size_t hs_idx = vol->hotspare_no; vol->hotspare_no++; + vol->hotspares[hs_idx].svc_id = hotspare; + hr_update_hotspare_status(vol, hs_idx, HR_EXT_HOTSPARE); + /* * If the volume is degraded, start rebuild right away. */ @@ -157,15 +165,18 @@ errno_t hr_raid1_add_hotspare(hr_volume_t *vol, service_id_t hotspare) HR_DEBUG("hr_raid1_add_hotspare(): volume in DEGRADED state, " "spawning new rebuild fibril\n"); fid_t fib = fibril_create(hr_raid1_rebuild, vol); - if (fib == 0) - return ENOMEM; + if (fib == 0) { + rc = ENOMEM; + goto error; + } fibril_start(fib); fibril_detach(fib); } - fibril_mutex_unlock(&vol->lock); +error: + fibril_mutex_unlock(&vol->hotspare_lock); - return EOK; + return rc; } static errno_t hr_raid1_bd_open(bd_srvs_t *bds, bd_srv_t *bd) @@ -213,66 +224,104 @@ static errno_t hr_raid1_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb) return EOK; } -static errno_t hr_raid1_check_vol_status(hr_volume_t *vol) +static void hr_raid1_update_vol_status(hr_volume_t *vol) { - if (vol->status == HR_VOL_ONLINE || - vol->status == HR_VOL_DEGRADED || - vol->status == HR_VOL_REBUILD) - return EOK; - return EIO; -} + fibril_rwlock_read_lock(&vol->extents_lock); + fibril_rwlock_read_lock(&vol->states_lock); -/* - * Update vol->status and return EOK if volume - * is usable - */ -static errno_t hr_raid1_update_vol_status(hr_volume_t *vol) -{ hr_vol_status_t old_state = vol->status; size_t healthy = hr_count_extents(vol, HR_EXT_ONLINE); + fibril_rwlock_read_unlock(&vol->states_lock); + fibril_rwlock_read_unlock(&vol->extents_lock); + if (healthy == 0) { - if (old_state != HR_VOL_FAULTY) + if (old_state != HR_VOL_FAULTY) { + fibril_rwlock_write_lock(&vol->states_lock); hr_update_vol_status(vol, HR_VOL_FAULTY); - return EIO; + fibril_rwlock_write_unlock(&vol->states_lock); + } } else if (healthy < vol->extent_no) { - if (old_state != HR_VOL_DEGRADED && - old_state != HR_VOL_REBUILD) { - - hr_update_vol_status(vol, HR_VOL_DEGRADED); + if (old_state != HR_VOL_REBUILD) { + if (old_state != HR_VOL_DEGRADED) { + fibril_rwlock_write_lock(&vol->states_lock); + hr_update_vol_status(vol, HR_VOL_DEGRADED); + fibril_rwlock_write_unlock(&vol->states_lock); + } if (vol->hotspare_no > 0) { fid_t fib = fibril_create(hr_raid1_rebuild, vol); if (fib == 0) - return ENOMEM; + return; fibril_start(fib); fibril_detach(fib); } } - return EOK; } else { - if (old_state != HR_VOL_ONLINE) + if (old_state != HR_VOL_ONLINE) { + fibril_rwlock_write_lock(&vol->states_lock); hr_update_vol_status(vol, HR_VOL_ONLINE); - return EOK; + fibril_rwlock_write_unlock(&vol->states_lock); + } } } -static void hr_raid1_handle_extent_error(hr_volume_t *vol, size_t extent, +static void hr_raid1_ext_state_callback(hr_volume_t *vol, size_t extent, errno_t rc) { - if (rc == ENOENT) + if (rc == EOK) + return; + + assert(fibril_rwlock_is_locked(&vol->extents_lock)); + + fibril_rwlock_write_lock(&vol->states_lock); + + switch (rc) { + case ENOENT: hr_update_ext_status(vol, extent, HR_EXT_MISSING); - else if (rc != EOK) + break; + default: hr_update_ext_status(vol, extent, HR_EXT_FAILED); + } + + fibril_rwlock_write_unlock(&vol->states_lock); +} + +static size_t hr_raid1_count_good_extents(hr_volume_t *vol, uint64_t ba, + size_t cnt, uint64_t rebuild_blk) +{ + assert(fibril_rwlock_is_locked(&vol->extents_lock)); + assert(fibril_rwlock_is_locked(&vol->states_lock)); + + size_t count = 0; + for (size_t i = 0; i < vol->extent_no; i++) { + if (vol->extents[i].status == HR_EXT_ONLINE || + (vol->extents[i].status == HR_EXT_REBUILD && + ba < rebuild_blk)) { + count++; + } + } + + return count; + } static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, size_t cnt, void *data_read, const void *data_write, size_t size) { hr_volume_t *vol = bd->srvs->sarg; + hr_range_lock_t *rl = NULL; errno_t rc; size_t i; + uint64_t rebuild_blk; + + fibril_rwlock_read_lock(&vol->states_lock); + hr_vol_status_t vol_state = vol->status; + fibril_rwlock_read_unlock(&vol->states_lock); + + if (vol_state == HR_VOL_FAULTY) + return EIO; if (type == HR_BD_READ || type == HR_BD_WRITE) if (size < cnt * vol->bsize) @@ -282,61 +331,122 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, if (rc != EOK) return rc; - hr_add_ba_offset(vol, &ba); + /* allow full dev sync */ + if (type != HR_BD_SYNC || ba != 0) + hr_add_ba_offset(vol, &ba); - fibril_mutex_lock(&vol->lock); + /* + * this is to allow adding hotspare or start a rebuild on + * very busy array, because of how rwlocks are implemented + * in HelenOS (no writer priority, so if there are multiple + * continuos readers, writer will never own the lock) + */ + if (vol->halt_please) { + fibril_mutex_lock(&vol->halt_lock); + fibril_mutex_unlock(&vol->halt_lock); + } - rc = hr_raid1_check_vol_status(vol); - if (rc != EOK) - goto end; + /* + * extent order has to be locked for the whole IO duration, + * so that workers have consistent targets + */ + fibril_rwlock_read_lock(&vol->extents_lock); size_t successful = 0; switch (type) { - case HR_BD_SYNC: - for (i = 0; i < vol->extent_no; i++) { - if (vol->extents[i].status != HR_EXT_ONLINE) - continue; - rc = block_sync_cache(vol->extents[i].svc_id, ba, cnt); - if (rc != EOK && rc != ENOTSUP) - hr_raid1_handle_extent_error(vol, i, rc); - else - successful++; - } - break; case HR_BD_READ: + rebuild_blk = atomic_load_explicit(&vol->rebuild_blk, + memory_order_relaxed); + for (i = 0; i < vol->extent_no; i++) { - if (vol->extents[i].status != HR_EXT_ONLINE) + fibril_rwlock_read_lock(&vol->states_lock); + hr_ext_status_t state = vol->extents[i].status; + fibril_rwlock_read_unlock(&vol->states_lock); + + if (state != HR_EXT_ONLINE && + (state != HR_EXT_REBUILD || + ba + cnt - 1 >= rebuild_blk)) { continue; + } + rc = block_read_direct(vol->extents[i].svc_id, ba, cnt, data_read); + + if (rc == ENOMEM && i + 1 == vol->extent_no) + goto end; + + if (rc == ENOMEM) + continue; + if (rc != EOK) { - hr_raid1_handle_extent_error(vol, i, rc); + hr_raid1_ext_state_callback(vol, i, rc); } else { successful++; break; } } break; + case HR_BD_SYNC: case HR_BD_WRITE: + if (type == HR_BD_WRITE) { + rl = hr_range_lock_acquire(vol, ba, cnt); + if (rl == NULL) { + rc = ENOMEM; + goto end; + } + } + + fibril_rwlock_read_lock(&vol->states_lock); + + rebuild_blk = atomic_load_explicit(&vol->rebuild_blk, + memory_order_relaxed); + + size_t good = hr_raid1_count_good_extents(vol, ba, cnt, + rebuild_blk); + + hr_fgroup_t *group = hr_fgroup_create(vol->fge, good); + if (group == NULL) { + if (type == HR_BD_WRITE) + hr_range_lock_release(rl); + rc = ENOMEM; + fibril_rwlock_read_unlock(&vol->states_lock); + goto end; + } + for (i = 0; i < vol->extent_no; i++) { - if (vol->extents[i].status != HR_EXT_ONLINE || - (vol->extents[i].status == HR_EXT_REBUILD && - ba >= vol->rebuild_blk)) + if (vol->extents[i].status != HR_EXT_ONLINE && + (vol->extents[i].status != HR_EXT_REBUILD || + ba >= rebuild_blk)) { /* * When the extent is being rebuilt, * we only write to the part that is already - * rebuilt. If ba is more than vol->rebuild_blk, - * the write is going to be replicated later - * in the rebuild. TODO: test + * rebuilt. If IO starts after vol->rebuild_blk + * we do not proceed, the write is going to + * be replicated later in the rebuild. */ continue; - rc = block_write_direct(vol->extents[i].svc_id, ba, cnt, - data_write); - if (rc != EOK) - hr_raid1_handle_extent_error(vol, i, rc); - else - successful++; + } + + hr_io_t *io = hr_fgroup_alloc(group); + io->extent = i; + io->data_write = data_write; + io->data_read = data_read; + io->ba = ba; + io->cnt = cnt; + io->type = type; + io->vol = vol; + io->state_callback = hr_raid1_ext_state_callback; + + hr_fgroup_submit(group, hr_io_worker, io); } + + fibril_rwlock_read_unlock(&vol->states_lock); + + (void)hr_fgroup_wait(group, &successful, NULL); + + if (type == HR_BD_WRITE) + hr_range_lock_release(rl); + break; default: rc = EINVAL; @@ -349,35 +459,61 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, rc = EIO; end: - (void)hr_raid1_update_vol_status(vol); - fibril_mutex_unlock(&vol->lock); + fibril_rwlock_read_unlock(&vol->extents_lock); + + hr_raid1_update_vol_status(vol); + return rc; } -/* - * Put the last HOTSPARE extent in place - * of first DEGRADED, and start the rebuild. - */ -static errno_t hr_raid1_rebuild(void *arg) +static errno_t swap_hs(hr_volume_t *vol, size_t bad, size_t hs) { - HR_DEBUG("hr_raid1_rebuild()\n"); + HR_DEBUG("hr_raid1_rebuild(): swapping in hotspare\n"); - hr_volume_t *vol = arg; - void *buf = NULL; + service_id_t faulty_svc_id = vol->extents[bad].svc_id; + service_id_t hs_svc_id = vol->hotspares[hs].svc_id; + + errno_t rc = block_init(hs_svc_id); + if (rc != EOK) { + HR_ERROR("hr_raid1_rebuild(): initing hotspare (%lu) failed\n", + hs_svc_id); + return rc; + } + + vol->extents[bad].svc_id = hs_svc_id; + hr_update_ext_status(vol, bad, HR_EXT_HOTSPARE); + + vol->hotspares[hs].svc_id = 0; + hr_update_hotspare_status(vol, hs, HR_EXT_INVALID); + + vol->hotspare_no--; + + if (faulty_svc_id != 0) + block_fini(faulty_svc_id); + + return EOK; +} + +static errno_t init_rebuild(hr_volume_t *vol, size_t *rebuild_idx) +{ errno_t rc = EOK; - fibril_mutex_lock(&vol->lock); + fibril_mutex_lock(&vol->halt_lock); + vol->halt_please = true; + fibril_rwlock_write_lock(&vol->extents_lock); + fibril_rwlock_write_lock(&vol->states_lock); + fibril_mutex_lock(&vol->hotspare_lock); if (vol->hotspare_no == 0) { HR_WARN("hr_raid1_rebuild(): no free hotspares on \"%s\", " "aborting rebuild\n", vol->devname); - /* retval isn't checked for now */ - goto end; + rc = EINVAL; + goto error; } size_t bad = vol->extent_no; for (size_t i = 0; i < vol->extent_no; i++) { - if (vol->extents[i].status == HR_EXT_FAILED) { + if (vol->extents[i].status != HR_EXT_ONLINE) { bad = i; break; } @@ -386,8 +522,8 @@ static errno_t hr_raid1_rebuild(void *arg) if (bad == vol->extent_no) { HR_WARN("hr_raid1_rebuild(): no bad extent on \"%s\", " "aborting rebuild\n", vol->devname); - /* retval isn't checked for now */ - goto end; + rc = EINVAL; + goto error; } size_t hotspare_idx = vol->hotspare_no - 1; @@ -397,111 +533,172 @@ static errno_t hr_raid1_rebuild(void *arg) HR_ERROR("hr_raid1_rebuild(): invalid hotspare state \"%s\", " "aborting rebuild\n", hr_get_ext_status_msg(hs_state)); rc = EINVAL; - goto end; + goto error; } - HR_DEBUG("hr_raid1_rebuild(): swapping in hotspare\n"); + rc = swap_hs(vol, bad, hotspare_idx); + if (rc != EOK) { + HR_ERROR("hr_raid1_rebuild(): swapping hotspare failed, " + "aborting rebuild\n"); + goto error; + } - block_fini(vol->extents[bad].svc_id); + hr_extent_t *rebuild_ext = &vol->extents[bad]; - vol->extents[bad].svc_id = vol->hotspares[hotspare_idx].svc_id; - hr_update_ext_status(vol, bad, HR_EXT_HOTSPARE); + HR_DEBUG("hr_raid1_rebuild(): starting REBUILD on extent no. %lu (%lu)" + "\n", bad, rebuild_ext->svc_id); - vol->hotspares[hotspare_idx].svc_id = 0; - hr_update_hotspare_status(vol, hotspare_idx, HR_EXT_MISSING); + atomic_store_explicit(&vol->rebuild_blk, 0, memory_order_relaxed); - vol->hotspare_no--; + hr_update_ext_status(vol, bad, HR_EXT_REBUILD); + hr_update_vol_status(vol, HR_VOL_REBUILD); - hr_extent_t *rebuild_ext = &vol->extents[bad]; + *rebuild_idx = bad; +error: + fibril_mutex_unlock(&vol->hotspare_lock); + fibril_rwlock_write_unlock(&vol->states_lock); + fibril_rwlock_write_unlock(&vol->extents_lock); + vol->halt_please = false; + fibril_mutex_unlock(&vol->halt_lock); + + return rc; +} + +static errno_t hr_raid1_restore_blocks(hr_volume_t *vol, size_t rebuild_idx, + uint64_t ba, size_t cnt, void *buf) +{ + HR_DEBUG("REBUILD restoring blocks (ba: %lu, cnt: %lu)\n", ba, cnt); + + assert(fibril_rwlock_is_locked(&vol->extents_lock)); - rc = block_init(rebuild_ext->svc_id); + errno_t rc = ENOENT; + hr_extent_t *ext, *rebuild_ext = &vol->extents[rebuild_idx]; + + for (size_t i = 0; i < vol->extent_no; i++) { + fibril_rwlock_read_lock(&vol->states_lock); + + ext = &vol->extents[i]; + if (ext->status != HR_EXT_ONLINE) + continue; + + fibril_rwlock_read_unlock(&vol->states_lock); + + rc = block_read_direct(ext->svc_id, ba, cnt, buf); + if (rc == EOK) + break; + + if (rc != ENOMEM) + hr_raid1_ext_state_callback(vol, i, rc); + + if (i + 1 >= vol->extent_no) { + HR_ERROR("rebuild on \"%s\" (%lu), failed due to " + "too many failed extents\n", + vol->devname, vol->svc_id); + + return rc; + } + } + + rc = block_write_direct(rebuild_ext->svc_id, ba, cnt, buf); if (rc != EOK) { - HR_ERROR("hr_raid1_rebuild(): initing (%lu) failed, " - "aborting rebuild\n", rebuild_ext->svc_id); - goto end; + if (rc != ENOMEM) + hr_raid1_ext_state_callback(vol, rebuild_idx, rc); + + HR_ERROR("rebuild on \"%s\" (%lu), failed due to " + "the rebuilt extent no. %lu WRITE (rc: %s)\n", + vol->devname, vol->svc_id, rebuild_idx, str_error(rc)); + + return rc; } - HR_DEBUG("hr_raid1_rebuild(): starting rebuild on (%lu)\n", - rebuild_ext->svc_id); + return EOK; +} - hr_update_ext_status(vol, bad, HR_EXT_REBUILD); - hr_update_vol_status(vol, HR_VOL_REBUILD); +/* + * Put the last HOTSPARE extent in place + * of first that != ONLINE, and start the rebuild. + */ +static errno_t hr_raid1_rebuild(void *arg) +{ + HR_DEBUG("hr_raid1_rebuild()\n"); + + hr_volume_t *vol = arg; + void *buf = NULL; + size_t rebuild_idx; + errno_t rc; + + rc = init_rebuild(vol, &rebuild_idx); + if (rc != EOK) + return rc; size_t left = vol->data_blkno; size_t max_blks = DATA_XFER_LIMIT / vol->bsize; buf = malloc(max_blks * vol->bsize); - hr_extent_t *ext; - - vol->rebuild_blk = 0; - size_t cnt; uint64_t ba = 0; hr_add_ba_offset(vol, &ba); + fibril_rwlock_read_lock(&vol->extents_lock); + + hr_range_lock_t *rl = NULL; + while (left != 0) { - vol->rebuild_blk = ba; - cnt = min(max_blks, left); - for (size_t i = 0; i < vol->extent_no; i++) { - ext = &vol->extents[i]; - if (ext->status == HR_EXT_ONLINE) { - rc = block_read_direct(ext->svc_id, ba, cnt, - buf); - if (rc != EOK) { - hr_raid1_handle_extent_error(vol, i, rc); - if (i + 1 < vol->extent_no) { - /* still might have one ONLINE */ - continue; - } else { - HR_ERROR("rebuild on \"%s\" (%lu), failed due to " - "too many failed extents\n", - vol->devname, vol->svc_id); - goto end; - } - } - break; - } + if (vol->halt_please) { + fibril_rwlock_read_unlock(&vol->extents_lock); + fibril_mutex_lock(&vol->halt_lock); + fibril_mutex_unlock(&vol->halt_lock); + fibril_rwlock_read_lock(&vol->extents_lock); } - rc = block_write_direct(rebuild_ext->svc_id, ba, cnt, buf); - if (rc != EOK) { - hr_raid1_handle_extent_error(vol, bad, rc); - HR_ERROR("rebuild on \"%s\" (%lu), failed due to " - "the rebuilt extent number %lu failing\n", - vol->devname, vol->svc_id, bad); - goto end; + cnt = min(max_blks, left); + rl = hr_range_lock_acquire(vol, ba, cnt); + if (rl == NULL) { + rc = ENOMEM; + goto end; } + atomic_store_explicit(&vol->rebuild_blk, ba, + memory_order_relaxed); + + rc = hr_raid1_restore_blocks(vol, rebuild_idx, ba, cnt, buf); + + hr_range_lock_release(rl); + + if (rc != EOK) + goto end; + ba += cnt; left -= cnt; - - /* - * Let other IO requests be served - * during rebuild. - */ - fibril_mutex_unlock(&vol->lock); - fibril_mutex_lock(&vol->lock); } HR_DEBUG("hr_raid1_rebuild(): rebuild finished on \"%s\" (%lu), " - "extent number %lu\n", vol->devname, vol->svc_id, hotspare_idx); + "extent no. %lu\n", vol->devname, vol->svc_id, rebuild_idx); + + fibril_rwlock_write_lock(&vol->states_lock); + hr_update_ext_status(vol, rebuild_idx, HR_EXT_ONLINE); + fibril_rwlock_write_unlock(&vol->states_lock); - hr_update_ext_status(vol, bad, HR_EXT_ONLINE); /* * For now write metadata at the end, because * we don't sync metada accross extents yet. */ - hr_write_meta_to_ext(vol, bad); + hr_write_meta_to_ext(vol, rebuild_idx); end: - (void)hr_raid1_update_vol_status(vol); + if (rc != EOK) { + fibril_rwlock_write_lock(&vol->states_lock); + hr_update_vol_status(vol, HR_VOL_DEGRADED); + fibril_rwlock_write_unlock(&vol->states_lock); + } + + fibril_rwlock_read_unlock(&vol->extents_lock); - fibril_mutex_unlock(&vol->lock); + hr_raid1_update_vol_status(vol); if (buf != NULL) free(buf); - /* retval isn't checked anywhere for now */ return rc; } diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index 499af1bbe5..8939d3146b 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -48,6 +48,7 @@ #define HR_STRIP_SIZE DATA_XFER_LIMIT +struct hr_volume; typedef struct hr_volume hr_volume_t; typedef struct hr_ops { @@ -86,21 +87,23 @@ typedef struct hr_volume { service_id_t svc_id; char devname[HR_DEVNAME_LEN]; - hr_extent_t extents[HR_MAX_EXTENTS]; size_t hotspare_no; hr_extent_t hotspares[HR_MAX_HOTSPARES]; - /* protects ordering (hr_extent_t.svc_id, hotspares) */ - fibril_rwlock_t extents_lock; + /* protects hotspares (hotspares.{svc_id,status}, hotspare_no) */ + fibril_mutex_t hotspare_lock; - /* protects states (hr_extent_t.status, hr_vol_status_t.status) */ + hr_extent_t extents[HR_MAX_EXTENTS]; + /* protects extents ordering (extents.svc_id) */ + fibril_rwlock_t extents_lock; + /* protects states (extents.status, hr_volume_t.status) */ fibril_rwlock_t states_lock; /* for halting IO requests when a REBUILD start waits */ bool halt_please; fibril_mutex_t halt_lock; - uint64_t rebuild_blk; + _Atomic uint64_t rebuild_blk; uint64_t counter; /* metadata syncing */ hr_vol_status_t status; } hr_volume_t; From 5ee041e2449b824f8d946b07e292f48eb3f6109b Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 12 Jan 2025 18:02:39 +0100 Subject: [PATCH 121/324] hr: RAID1: deferred extent invalidation --- uspace/srv/bd/hr/hr.c | 3 ++ uspace/srv/bd/hr/raid1.c | 82 ++++++++++++++++++++++++++++++++++++++++ uspace/srv/bd/hr/var.h | 19 +++++++++- 3 files changed, 103 insertions(+), 1 deletion(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 2687196b02..4d4b4e5b72 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -259,6 +259,9 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) list_initialize(&new_volume->range_lock_list); fibril_mutex_initialize(&new_volume->range_lock_list_lock); + fibril_mutex_initialize(&new_volume->deferred_list_lock); + list_initialize(&new_volume->deferred_invalidations_list); + atomic_init(&new_volume->rebuild_blk, 0); rc = new_volume->hr_ops.create(new_volume); diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index a6ffb61b76..50d6ca5952 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -55,6 +55,7 @@ extern loc_srv_t *hr_srv; +static void process_deferred_invalidations(hr_volume_t *); static void hr_raid1_update_vol_status(hr_volume_t *); static void hr_raid1_ext_state_callback(hr_volume_t *, size_t, errno_t); static size_t hr_raid1_count_good_extents(hr_volume_t *, uint64_t, size_t, @@ -224,8 +225,62 @@ static errno_t hr_raid1_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb) return EOK; } +static void process_deferred_invalidations(hr_volume_t *vol) +{ + HR_DEBUG("hr_raid1_update_vol_status(): deferred invalidations\n"); + + fibril_mutex_lock(&vol->halt_lock); + vol->halt_please = true; + fibril_rwlock_write_lock(&vol->extents_lock); + fibril_rwlock_write_lock(&vol->states_lock); + fibril_mutex_lock(&vol->hotspare_lock); + + list_foreach(vol->deferred_invalidations_list, link, + hr_deferred_invalidation_t, di) { + assert(vol->extents[di->index].status == HR_EXT_INVALID); + + HR_DEBUG("moving invalidated extent no. %lu to hotspares\n", + di->index); + + block_fini(di->svc_id); + + size_t hs_idx = vol->hotspare_no; + + vol->hotspare_no++; + + vol->hotspares[hs_idx].svc_id = di->svc_id; + hr_update_hotspare_status(vol, hs_idx, HR_EXT_HOTSPARE); + + vol->extents[di->index].svc_id = 0; + hr_update_ext_status(vol, di->index, HR_EXT_MISSING); + + assert(vol->hotspare_no < HR_MAX_HOTSPARES + HR_MAX_EXTENTS); + } + + for (size_t i = 0; i < HR_MAX_EXTENTS; i++) { + hr_deferred_invalidation_t *di = &vol->deferred_inval[i]; + if (di->svc_id != 0) { + list_remove(&di->link); + di->svc_id = 0; + } + } + + fibril_mutex_unlock(&vol->hotspare_lock); + fibril_rwlock_write_unlock(&vol->states_lock); + fibril_rwlock_write_unlock(&vol->extents_lock); + vol->halt_please = false; + fibril_mutex_unlock(&vol->halt_lock); +} + static void hr_raid1_update_vol_status(hr_volume_t *vol) { + fibril_mutex_lock(&vol->deferred_list_lock); + + if (list_count(&vol->deferred_invalidations_list) > 0) + process_deferred_invalidations(vol); + + fibril_mutex_unlock(&vol->deferred_list_lock); + fibril_rwlock_read_lock(&vol->extents_lock); fibril_rwlock_read_lock(&vol->states_lock); @@ -278,6 +333,33 @@ static void hr_raid1_ext_state_callback(hr_volume_t *vol, size_t extent, fibril_rwlock_write_lock(&vol->states_lock); switch (rc) { + case ENOMEM: + fibril_mutex_lock(&vol->deferred_list_lock); + + service_id_t invalid_svc_id = vol->extents[extent].svc_id; + + list_foreach(vol->deferred_invalidations_list, link, + hr_deferred_invalidation_t, di) { + if (di->svc_id == invalid_svc_id) { + assert(vol->extents[extent].status == + HR_EXT_INVALID); + goto done; + } + } + + assert(vol->extents[extent].svc_id != HR_EXT_INVALID); + + hr_update_ext_status(vol, extent, HR_EXT_INVALID); + + size_t i = list_count(&vol->deferred_invalidations_list); + vol->deferred_inval[i].svc_id = invalid_svc_id; + vol->deferred_inval[i].index = extent; + + list_append(&vol->deferred_inval[i].link, + &vol->deferred_invalidations_list); + done: + fibril_mutex_unlock(&vol->deferred_list_lock); + break; case ENOENT: hr_update_ext_status(vol, extent, HR_EXT_MISSING); break; diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index 8939d3146b..36a34a0798 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -58,6 +58,12 @@ typedef struct hr_ops { errno_t (*add_hotspare)(hr_volume_t *, service_id_t); } hr_ops_t; +typedef struct hr_deferred_invalidation { + link_t link; + size_t index; + service_id_t svc_id; +} hr_deferred_invalidation_t; + typedef struct hr_volume { hr_ops_t hr_ops; bd_srvs_t hr_bds; @@ -88,7 +94,7 @@ typedef struct hr_volume { char devname[HR_DEVNAME_LEN]; size_t hotspare_no; - hr_extent_t hotspares[HR_MAX_HOTSPARES]; + hr_extent_t hotspares[HR_MAX_HOTSPARES + HR_MAX_EXTENTS]; /* protects hotspares (hotspares.{svc_id,status}, hotspare_no) */ fibril_mutex_t hotspare_lock; @@ -103,6 +109,17 @@ typedef struct hr_volume { bool halt_please; fibril_mutex_t halt_lock; + /* + * For deferring invalidations of extents. Used when + * an extent has to be invalidated (got ENOMEM on a WRITE), + * but workers - therefore state callbacks cannot lock + * extents for writing (they are readers), so invalidations + * are harvested later when we are able to. + */ + fibril_mutex_t deferred_list_lock; + list_t deferred_invalidations_list; + hr_deferred_invalidation_t deferred_inval[HR_MAX_EXTENTS]; + _Atomic uint64_t rebuild_blk; uint64_t counter; /* metadata syncing */ hr_vol_status_t status; From 3a68baab70c3a34b7d36d95e7573dc8db1dcad3b Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 12 Jan 2025 22:21:03 +0100 Subject: [PATCH 122/324] lib/device/hr: add INVALID state --- uspace/lib/device/include/hr.h | 4 +++- uspace/lib/device/src/hr.c | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index a6f235f0ae..85b9ae56a0 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -67,13 +67,15 @@ typedef enum hr_level { #define HR_RLQ_RAID5_NC 0x03 /* RAID-5 Rotating Parity N with Data Continuation */ typedef enum hr_vol_status { - HR_VOL_ONLINE, /* OK, OPTIMAL */ + HR_VOL_INVALID, + HR_VOL_ONLINE, /* OPTIMAL */ HR_VOL_FAULTY, HR_VOL_DEGRADED, /* also used for partial, but usable mirror */ HR_VOL_REBUILD } hr_vol_status_t; typedef enum hr_ext_status { + HR_EXT_INVALID, HR_EXT_ONLINE, /* OK */ HR_EXT_MISSING, HR_EXT_FAILED, diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index 999ebb9f17..a9cf859403 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -320,6 +320,8 @@ errno_t hr_print_status(void) const char *hr_get_vol_status_msg(hr_vol_status_t status) { switch (status) { + case HR_VOL_INVALID: + return "INVALID"; case HR_VOL_ONLINE: return "ONLINE"; case HR_VOL_FAULTY: @@ -336,6 +338,8 @@ const char *hr_get_vol_status_msg(hr_vol_status_t status) const char *hr_get_ext_status_msg(hr_ext_status_t status) { switch (status) { + case HR_EXT_INVALID: + return "INVALID"; case HR_EXT_ONLINE: return "ONLINE"; case HR_EXT_MISSING: From 36661772fee5a252907eec78afc8a94774e88675 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 12 Jan 2025 18:03:54 +0100 Subject: [PATCH 123/324] hr: util.c: add assertions for locks --- uspace/srv/bd/hr/util.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 766d64d4cf..bc7f349a58 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Miroslav Cimerman + * Copyright (c) 2025 Miroslav Cimerman * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -92,7 +92,7 @@ void hr_fini_devs(hr_volume_t *vol) size_t i; for (i = 0; i < vol->extent_no; i++) { - if (vol->extents[i].status != HR_EXT_MISSING) { + if (vol->extents[i].svc_id != 0) { HR_DEBUG("hr_fini_devs(): block_fini() on (%lu)\n", vol->extents[i].svc_id); block_fini(vol->extents[i].svc_id); @@ -212,6 +212,11 @@ void hr_add_ba_offset(hr_volume_t *vol, uint64_t *ba) void hr_update_ext_status(hr_volume_t *vol, size_t extent, hr_ext_status_t s) { + if (vol->level != HR_LVL_0) + assert(fibril_rwlock_is_locked(&vol->extents_lock)); + + assert(fibril_rwlock_is_write_locked(&vol->states_lock)); + assert(extent < vol->extent_no); hr_ext_status_t old = vol->extents[extent].status; @@ -223,6 +228,8 @@ void hr_update_ext_status(hr_volume_t *vol, size_t extent, hr_ext_status_t s) void hr_update_hotspare_status(hr_volume_t *vol, size_t hs, hr_ext_status_t s) { + assert(fibril_mutex_is_locked(&vol->hotspare_lock)); + assert(hs < vol->hotspare_no); hr_ext_status_t old = vol->hotspares[hs].status; @@ -234,6 +241,8 @@ void hr_update_hotspare_status(hr_volume_t *vol, size_t hs, hr_ext_status_t s) void hr_update_vol_status(hr_volume_t *vol, hr_vol_status_t s) { + assert(fibril_rwlock_is_write_locked(&vol->states_lock)); + HR_WARN("\"%s\": changing volume state: %s -> %s\n", vol->devname, hr_get_vol_status_msg(vol->status), hr_get_vol_status_msg(s)); vol->status = s; @@ -255,7 +264,9 @@ void hr_sync_all_extents(hr_volume_t *vol) if (vol->extents[i].status != HR_EXT_ONLINE) continue; rc = block_sync_cache(vol->extents[i].svc_id, 0, 0); - if (rc != EOK && rc != ENOTSUP) { + if (rc == ENOMEM || rc == ENOTSUP) + continue; + if (rc != EOK) { if (rc == ENOENT) hr_update_ext_status(vol, i, HR_EXT_MISSING); else if (rc != EOK) @@ -267,6 +278,10 @@ void hr_sync_all_extents(hr_volume_t *vol) size_t hr_count_extents(hr_volume_t *vol, hr_ext_status_t status) { + if (vol->level != HR_LVL_0) + assert(fibril_rwlock_is_locked(&vol->extents_lock)); + assert(fibril_rwlock_is_locked(&vol->states_lock)); + size_t count = 0; for (size_t i = 0; i < vol->extent_no; i++) if (vol->extents[i].status == status) @@ -338,6 +353,9 @@ hr_range_lock_t *hr_range_lock_acquire(hr_volume_t *vol, uint64_t ba, void hr_range_lock_release(hr_range_lock_t *rl) { + if (rl == NULL) + return; + HR_RL_LIST_LOCK(rl->vol); rl->pending--; From edc89bd8532222d0daa40cad5eaddcc88db69245 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 12 Jan 2025 18:19:43 +0100 Subject: [PATCH 124/324] hr: util: add hr_update_{ext,hotspare}_svc_id() Provides easy way to assert write-ownership of needed locks. --- uspace/srv/bd/hr/util.c | 31 ++++++++++++++++++++++++++++--- uspace/srv/bd/hr/util.h | 2 ++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index bc7f349a58..fbfef6362a 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -239,13 +239,38 @@ void hr_update_hotspare_status(hr_volume_t *vol, size_t hs, hr_ext_status_t s) vol->hotspares[hs].status = s; } -void hr_update_vol_status(hr_volume_t *vol, hr_vol_status_t s) +void hr_update_vol_status(hr_volume_t *vol, hr_vol_status_t new) { assert(fibril_rwlock_is_write_locked(&vol->states_lock)); HR_WARN("\"%s\": changing volume state: %s -> %s\n", vol->devname, - hr_get_vol_status_msg(vol->status), hr_get_vol_status_msg(s)); - vol->status = s; + hr_get_vol_status_msg(vol->status), hr_get_vol_status_msg(new)); + vol->status = new; +} + +void hr_update_ext_svc_id(hr_volume_t *vol, size_t extent, service_id_t new) +{ + if (vol->level != HR_LVL_0) + assert(fibril_rwlock_is_write_locked(&vol->extents_lock)); + + assert(extent < vol->extent_no); + + service_id_t old = vol->extents[extent].svc_id; + HR_WARN("\"%s\": changing extent no. %lu svc_id: (%lu) -> (%lu)\n", + vol->devname, extent, old, new); + vol->extents[extent].svc_id = new; +} + +void hr_update_hotspare_svc_id(hr_volume_t *vol, size_t hs, service_id_t new) +{ + assert(fibril_mutex_is_locked(&vol->hotspare_lock)); + + assert(hs < vol->hotspare_no); + + service_id_t old = vol->hotspares[hs].svc_id; + HR_WARN("\"%s\": changing hotspare no. %lu svc_id: (%lu) -> (%lu)\n", + vol->devname, hs, old, new); + vol->hotspares[hs].svc_id = new; } /* diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index 59f59e7e30..7489afc0e7 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -59,6 +59,8 @@ extern void hr_add_ba_offset(hr_volume_t *, uint64_t *); extern void hr_update_ext_status(hr_volume_t *, size_t, hr_ext_status_t); extern void hr_update_hotspare_status(hr_volume_t *, size_t, hr_ext_status_t); extern void hr_update_vol_status(hr_volume_t *, hr_vol_status_t); +extern void hr_update_ext_svc_id(hr_volume_t *, size_t, service_id_t); +extern void hr_update_hotspare_svc_id(hr_volume_t *, size_t, service_id_t); extern void hr_sync_all_extents(hr_volume_t *); extern size_t hr_count_extents(hr_volume_t *, hr_ext_status_t); extern hr_range_lock_t *hr_range_lock_acquire(hr_volume_t *, uint64_t, From e2b417fb8e7a6702a6b892e56aeb05aaca322df1 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 12 Jan 2025 18:21:40 +0100 Subject: [PATCH 125/324] hr: RAID1: use update_svc_id() wrappers from util --- uspace/srv/bd/hr/raid1.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 50d6ca5952..fec17c1c20 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -156,7 +156,7 @@ errno_t hr_raid1_add_hotspare(hr_volume_t *vol, service_id_t hotspare) vol->hotspare_no++; - vol->hotspares[hs_idx].svc_id = hotspare; + hr_update_hotspare_svc_id(vol, hs_idx, hotspare); hr_update_hotspare_status(vol, hs_idx, HR_EXT_HOTSPARE); /* @@ -248,10 +248,10 @@ static void process_deferred_invalidations(hr_volume_t *vol) vol->hotspare_no++; - vol->hotspares[hs_idx].svc_id = di->svc_id; + hr_update_hotspare_svc_id(vol, hs_idx, di->svc_id); hr_update_hotspare_status(vol, hs_idx, HR_EXT_HOTSPARE); - vol->extents[di->index].svc_id = 0; + hr_update_ext_svc_id(vol, di->index, 0); hr_update_ext_status(vol, di->index, HR_EXT_MISSING); assert(vol->hotspare_no < HR_MAX_HOTSPARES + HR_MAX_EXTENTS); @@ -562,10 +562,10 @@ static errno_t swap_hs(hr_volume_t *vol, size_t bad, size_t hs) return rc; } - vol->extents[bad].svc_id = hs_svc_id; + hr_update_ext_svc_id(vol, bad, hs_svc_id); hr_update_ext_status(vol, bad, HR_EXT_HOTSPARE); - vol->hotspares[hs].svc_id = 0; + hr_update_hotspare_svc_id(vol, hs, 0); hr_update_hotspare_status(vol, hs, HR_EXT_INVALID); vol->hotspare_no--; From 401b9e42596ee6f79ffb72abcea7c66e9878f990 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 12 Jan 2025 20:18:08 +0100 Subject: [PATCH 126/324] hr: state_changed and peding_invalidation atomic flags These flags are used to check whether there was a state change, or if there is a pending invalidation, so that we can avoid the slow code paths in a lockless fashion. --- uspace/srv/bd/hr/hr.c | 6 ++++++ uspace/srv/bd/hr/raid1.c | 24 ++++++++++++++++++------ uspace/srv/bd/hr/var.h | 2 ++ 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 4d4b4e5b72..e2c12c3c34 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -263,6 +263,8 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) list_initialize(&new_volume->deferred_invalidations_list); atomic_init(&new_volume->rebuild_blk, 0); + atomic_init(&new_volume->state_changed, false); + atomic_init(&new_volume->pending_invalidation, false); rc = new_volume->hr_ops.create(new_volume); if (rc != EOK) @@ -319,7 +321,11 @@ static void hr_stop_srv(ipc_call_t *icall) } else { fibril_rwlock_write_lock(&vol->states_lock); fibril_rwlock_read_lock(&vol->extents_lock); + + /* TODO: maybe expose extent state callbacks */ hr_update_ext_status(vol, fail_extent, HR_EXT_FAILED); + atomic_store(&vol->state_changed, true); + fibril_rwlock_read_unlock(&vol->extents_lock); fibril_rwlock_write_unlock(&vol->states_lock); diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index fec17c1c20..9bfb912811 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -102,6 +102,8 @@ errno_t hr_raid1_create(hr_volume_t *new_volume) new_volume->hr_bds.ops = &hr_raid1_bd_ops; new_volume->hr_bds.sarg = new_volume; + /* force volume state update */ + atomic_store(&new_volume->state_changed, true); hr_raid1_update_vol_status(new_volume); if (new_volume->status == HR_VOL_FAULTY) return EINVAL; @@ -274,12 +276,17 @@ static void process_deferred_invalidations(hr_volume_t *vol) static void hr_raid1_update_vol_status(hr_volume_t *vol) { - fibril_mutex_lock(&vol->deferred_list_lock); + bool exp = true; - if (list_count(&vol->deferred_invalidations_list) > 0) - process_deferred_invalidations(vol); + if (!atomic_compare_exchange_strong(&vol->state_changed, &exp, false)) + return; - fibril_mutex_unlock(&vol->deferred_list_lock); + if (atomic_compare_exchange_strong(&vol->pending_invalidation, &exp, + false)) { + fibril_mutex_lock(&vol->deferred_list_lock); + process_deferred_invalidations(vol); + fibril_mutex_unlock(&vol->deferred_list_lock); + } fibril_rwlock_read_lock(&vol->extents_lock); fibril_rwlock_read_lock(&vol->states_lock); @@ -343,7 +350,7 @@ static void hr_raid1_ext_state_callback(hr_volume_t *vol, size_t extent, if (di->svc_id == invalid_svc_id) { assert(vol->extents[extent].status == HR_EXT_INVALID); - goto done; + goto deferring_end; } } @@ -357,7 +364,10 @@ static void hr_raid1_ext_state_callback(hr_volume_t *vol, size_t extent, list_append(&vol->deferred_inval[i].link, &vol->deferred_invalidations_list); - done: + + atomic_store(&vol->pending_invalidation, true); + deferring_end: + fibril_mutex_unlock(&vol->deferred_list_lock); break; case ENOENT: @@ -367,6 +377,8 @@ static void hr_raid1_ext_state_callback(hr_volume_t *vol, size_t extent, hr_update_ext_status(vol, extent, HR_EXT_FAILED); } + atomic_store(&vol->state_changed, true); + fibril_rwlock_write_unlock(&vol->states_lock); } diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index 36a34a0798..ee65adf664 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -116,10 +116,12 @@ typedef struct hr_volume { * extents for writing (they are readers), so invalidations * are harvested later when we are able to. */ + _Atomic bool pending_invalidation; fibril_mutex_t deferred_list_lock; list_t deferred_invalidations_list; hr_deferred_invalidation_t deferred_inval[HR_MAX_EXTENTS]; + _Atomic bool state_changed; _Atomic uint64_t rebuild_blk; uint64_t counter; /* metadata syncing */ hr_vol_status_t status; From dec41507e0de0bebfee6a879cf9990d06233a20a Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 12 Jan 2025 21:11:54 +0100 Subject: [PATCH 127/324] hr: RAID1: fix unsafe access in add_hotspare() --- uspace/srv/bd/hr/raid1.c | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 9bfb912811..69c9010c0a 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -161,24 +161,12 @@ errno_t hr_raid1_add_hotspare(hr_volume_t *vol, service_id_t hotspare) hr_update_hotspare_svc_id(vol, hs_idx, hotspare); hr_update_hotspare_status(vol, hs_idx, HR_EXT_HOTSPARE); - /* - * If the volume is degraded, start rebuild right away. - */ - if (vol->status == HR_VOL_DEGRADED) { - HR_DEBUG("hr_raid1_add_hotspare(): volume in DEGRADED state, " - "spawning new rebuild fibril\n"); - fid_t fib = fibril_create(hr_raid1_rebuild, vol); - if (fib == 0) { - rc = ENOMEM; - goto error; - } - fibril_start(fib); - fibril_detach(fib); - } - + atomic_store(&vol->state_changed, true); error: fibril_mutex_unlock(&vol->hotspare_lock); + hr_raid1_update_vol_status(vol); + return rc; } @@ -304,13 +292,14 @@ static void hr_raid1_update_vol_status(hr_volume_t *vol) fibril_rwlock_write_unlock(&vol->states_lock); } } else if (healthy < vol->extent_no) { - if (old_state != HR_VOL_REBUILD) { - if (old_state != HR_VOL_DEGRADED) { - fibril_rwlock_write_lock(&vol->states_lock); - hr_update_vol_status(vol, HR_VOL_DEGRADED); - fibril_rwlock_write_unlock(&vol->states_lock); - } + if (old_state != HR_VOL_REBUILD && + old_state != HR_VOL_DEGRADED) { + fibril_rwlock_write_lock(&vol->states_lock); + hr_update_vol_status(vol, HR_VOL_DEGRADED); + fibril_rwlock_write_unlock(&vol->states_lock); + } + if (old_state != HR_VOL_REBUILD) { if (vol->hotspare_no > 0) { fid_t fib = fibril_create(hr_raid1_rebuild, vol); From d773bea92b783e9dcfd88271e9fa601ccfa34c0a Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 12 Jan 2025 21:12:46 +0100 Subject: [PATCH 128/324] hr: RAID1: handle state edge cases in a rebuild --- uspace/srv/bd/hr/raid1.c | 47 +++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 69c9010c0a..7fe2914da7 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -674,9 +674,21 @@ static errno_t hr_raid1_restore_blocks(hr_volume_t *vol, size_t rebuild_idx, hr_raid1_ext_state_callback(vol, i, rc); if (i + 1 >= vol->extent_no) { - HR_ERROR("rebuild on \"%s\" (%lu), failed due to " - "too many failed extents\n", - vol->devname, vol->svc_id); + if (rc != ENOMEM) { + HR_ERROR("rebuild on \"%s\" (%lu), failed due " + "to too many failed extents\n", + vol->devname, vol->svc_id); + } + + /* for now we have to invalidate the rebuild extent */ + if (rc == ENOMEM) { + HR_ERROR("rebuild on \"%s\" (%lu), failed due " + "to too many failed reads, because of not " + "enough memory\n", + vol->devname, vol->svc_id); + hr_raid1_ext_state_callback(vol, rebuild_idx, + ENOMEM); + } return rc; } @@ -684,8 +696,15 @@ static errno_t hr_raid1_restore_blocks(hr_volume_t *vol, size_t rebuild_idx, rc = block_write_direct(rebuild_ext->svc_id, ba, cnt, buf); if (rc != EOK) { - if (rc != ENOMEM) - hr_raid1_ext_state_callback(vol, rebuild_idx, rc); + /* + * Here we dont handle ENOMEM, because maybe in the + * future, there is going to be M_WAITOK, or we are + * going to wait for more memory, so that we don't + * have to invalidate it... + * + * XXX: for now we do + */ + hr_raid1_ext_state_callback(vol, rebuild_idx, rc); HR_ERROR("rebuild on \"%s\" (%lu), failed due to " "the rebuilt extent no. %lu WRITE (rc: %s)\n", @@ -760,7 +779,17 @@ static errno_t hr_raid1_rebuild(void *arg) "extent no. %lu\n", vol->devname, vol->svc_id, rebuild_idx); fibril_rwlock_write_lock(&vol->states_lock); + hr_update_ext_status(vol, rebuild_idx, HR_EXT_ONLINE); + /* + * We can be optimistic here, if some extents are + * still INVALID, FAULTY or MISSING, the update vol + * function will pick them up, and set the volume + * state accordingly. + */ + hr_update_vol_status(vol, HR_VOL_ONLINE); + atomic_store(&vol->state_changed, true); + fibril_rwlock_write_unlock(&vol->states_lock); /* @@ -770,8 +799,16 @@ static errno_t hr_raid1_rebuild(void *arg) hr_write_meta_to_ext(vol, rebuild_idx); end: if (rc != EOK) { + /* + * We can fail either because: + * - the rebuild extent failing or invalidation + * - there is are no ONLINE extents (vol is FAULTY) + * - we got ENOMEM on all READs (we also invalidate the + * rebuild extent here, for now) + */ fibril_rwlock_write_lock(&vol->states_lock); hr_update_vol_status(vol, HR_VOL_DEGRADED); + atomic_store(&vol->state_changed, true); fibril_rwlock_write_unlock(&vol->states_lock); } From 35f2a8775560131cbaaf183620f8bd821e7c4ae8 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 12 Jan 2025 21:34:12 +0100 Subject: [PATCH 129/324] hr: raid1.c: move around static functions --- uspace/srv/bd/hr/raid1.c | 317 ++++++++++++++++++++------------------- 1 file changed, 160 insertions(+), 157 deletions(-) diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 7fe2914da7..4e080076db 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -55,16 +55,18 @@ extern loc_srv_t *hr_srv; -static void process_deferred_invalidations(hr_volume_t *); static void hr_raid1_update_vol_status(hr_volume_t *); static void hr_raid1_ext_state_callback(hr_volume_t *, size_t, errno_t); static size_t hr_raid1_count_good_extents(hr_volume_t *, uint64_t, size_t, uint64_t); static errno_t hr_raid1_bd_op(hr_bd_op_type_t, bd_srv_t *, aoff64_t, size_t, void *, const void *, size_t); -static errno_t swap_hs(hr_volume_t *, size_t, size_t); -static errno_t init_rebuild(hr_volume_t *, size_t *); static errno_t hr_raid1_rebuild(void *); +static errno_t init_rebuild(hr_volume_t *, size_t *); +static errno_t swap_hs(hr_volume_t *, size_t, size_t); +static errno_t hr_raid1_restore_blocks(hr_volume_t *, size_t, uint64_t, size_t, + void *); +static void hr_process_deferred_invalidations(hr_volume_t *); /* bdops */ static errno_t hr_raid1_bd_open(bd_srvs_t *, bd_srv_t *); @@ -215,53 +217,6 @@ static errno_t hr_raid1_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb) return EOK; } -static void process_deferred_invalidations(hr_volume_t *vol) -{ - HR_DEBUG("hr_raid1_update_vol_status(): deferred invalidations\n"); - - fibril_mutex_lock(&vol->halt_lock); - vol->halt_please = true; - fibril_rwlock_write_lock(&vol->extents_lock); - fibril_rwlock_write_lock(&vol->states_lock); - fibril_mutex_lock(&vol->hotspare_lock); - - list_foreach(vol->deferred_invalidations_list, link, - hr_deferred_invalidation_t, di) { - assert(vol->extents[di->index].status == HR_EXT_INVALID); - - HR_DEBUG("moving invalidated extent no. %lu to hotspares\n", - di->index); - - block_fini(di->svc_id); - - size_t hs_idx = vol->hotspare_no; - - vol->hotspare_no++; - - hr_update_hotspare_svc_id(vol, hs_idx, di->svc_id); - hr_update_hotspare_status(vol, hs_idx, HR_EXT_HOTSPARE); - - hr_update_ext_svc_id(vol, di->index, 0); - hr_update_ext_status(vol, di->index, HR_EXT_MISSING); - - assert(vol->hotspare_no < HR_MAX_HOTSPARES + HR_MAX_EXTENTS); - } - - for (size_t i = 0; i < HR_MAX_EXTENTS; i++) { - hr_deferred_invalidation_t *di = &vol->deferred_inval[i]; - if (di->svc_id != 0) { - list_remove(&di->link); - di->svc_id = 0; - } - } - - fibril_mutex_unlock(&vol->hotspare_lock); - fibril_rwlock_write_unlock(&vol->states_lock); - fibril_rwlock_write_unlock(&vol->extents_lock); - vol->halt_please = false; - fibril_mutex_unlock(&vol->halt_lock); -} - static void hr_raid1_update_vol_status(hr_volume_t *vol) { bool exp = true; @@ -272,7 +227,7 @@ static void hr_raid1_update_vol_status(hr_volume_t *vol) if (atomic_compare_exchange_strong(&vol->pending_invalidation, &exp, false)) { fibril_mutex_lock(&vol->deferred_list_lock); - process_deferred_invalidations(vol); + hr_process_deferred_invalidations(vol); fibril_mutex_unlock(&vol->deferred_list_lock); } @@ -549,32 +504,110 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, return rc; } -static errno_t swap_hs(hr_volume_t *vol, size_t bad, size_t hs) +/* + * Put the last HOTSPARE extent in place + * of first that != ONLINE, and start the rebuild. + */ +static errno_t hr_raid1_rebuild(void *arg) { - HR_DEBUG("hr_raid1_rebuild(): swapping in hotspare\n"); + HR_DEBUG("hr_raid1_rebuild()\n"); - service_id_t faulty_svc_id = vol->extents[bad].svc_id; - service_id_t hs_svc_id = vol->hotspares[hs].svc_id; + hr_volume_t *vol = arg; + void *buf = NULL; + size_t rebuild_idx; + errno_t rc; - errno_t rc = block_init(hs_svc_id); - if (rc != EOK) { - HR_ERROR("hr_raid1_rebuild(): initing hotspare (%lu) failed\n", - hs_svc_id); + rc = init_rebuild(vol, &rebuild_idx); + if (rc != EOK) return rc; + + size_t left = vol->data_blkno; + size_t max_blks = DATA_XFER_LIMIT / vol->bsize; + buf = malloc(max_blks * vol->bsize); + + size_t cnt; + uint64_t ba = 0; + hr_add_ba_offset(vol, &ba); + + fibril_rwlock_read_lock(&vol->extents_lock); + + hr_range_lock_t *rl = NULL; + + while (left != 0) { + if (vol->halt_please) { + fibril_rwlock_read_unlock(&vol->extents_lock); + fibril_mutex_lock(&vol->halt_lock); + fibril_mutex_unlock(&vol->halt_lock); + fibril_rwlock_read_lock(&vol->extents_lock); + } + + cnt = min(max_blks, left); + + rl = hr_range_lock_acquire(vol, ba, cnt); + if (rl == NULL) { + rc = ENOMEM; + goto end; + } + + atomic_store_explicit(&vol->rebuild_blk, ba, + memory_order_relaxed); + + rc = hr_raid1_restore_blocks(vol, rebuild_idx, ba, cnt, buf); + + hr_range_lock_release(rl); + + if (rc != EOK) + goto end; + + ba += cnt; + left -= cnt; } - hr_update_ext_svc_id(vol, bad, hs_svc_id); - hr_update_ext_status(vol, bad, HR_EXT_HOTSPARE); + HR_DEBUG("hr_raid1_rebuild(): rebuild finished on \"%s\" (%lu), " + "extent no. %lu\n", vol->devname, vol->svc_id, rebuild_idx); - hr_update_hotspare_svc_id(vol, hs, 0); - hr_update_hotspare_status(vol, hs, HR_EXT_INVALID); + fibril_rwlock_write_lock(&vol->states_lock); - vol->hotspare_no--; + hr_update_ext_status(vol, rebuild_idx, HR_EXT_ONLINE); + /* + * We can be optimistic here, if some extents are + * still INVALID, FAULTY or MISSING, the update vol + * function will pick them up, and set the volume + * state accordingly. + */ + hr_update_vol_status(vol, HR_VOL_ONLINE); + atomic_store(&vol->state_changed, true); - if (faulty_svc_id != 0) - block_fini(faulty_svc_id); + fibril_rwlock_write_unlock(&vol->states_lock); - return EOK; + /* + * For now write metadata at the end, because + * we don't sync metada accross extents yet. + */ + hr_write_meta_to_ext(vol, rebuild_idx); +end: + if (rc != EOK) { + /* + * We can fail either because: + * - the rebuild extent failing or invalidation + * - there is are no ONLINE extents (vol is FAULTY) + * - we got ENOMEM on all READs (we also invalidate the + * rebuild extent here, for now) + */ + fibril_rwlock_write_lock(&vol->states_lock); + hr_update_vol_status(vol, HR_VOL_DEGRADED); + atomic_store(&vol->state_changed, true); + fibril_rwlock_write_unlock(&vol->states_lock); + } + + fibril_rwlock_read_unlock(&vol->extents_lock); + + hr_raid1_update_vol_status(vol); + + if (buf != NULL) + free(buf); + + return rc; } static errno_t init_rebuild(hr_volume_t *vol, size_t *rebuild_idx) @@ -647,6 +680,35 @@ static errno_t init_rebuild(hr_volume_t *vol, size_t *rebuild_idx) return rc; } +static errno_t swap_hs(hr_volume_t *vol, size_t bad, size_t hs) +{ + HR_DEBUG("hr_raid1_rebuild(): swapping in hotspare\n"); + + service_id_t faulty_svc_id = vol->extents[bad].svc_id; + service_id_t hs_svc_id = vol->hotspares[hs].svc_id; + + /* TODO: if rc != EOK, try next hotspare */ + errno_t rc = block_init(hs_svc_id); + if (rc != EOK) { + HR_ERROR("hr_raid1_rebuild(): initing hotspare (%lu) failed\n", + hs_svc_id); + return rc; + } + + hr_update_ext_svc_id(vol, bad, hs_svc_id); + hr_update_ext_status(vol, bad, HR_EXT_HOTSPARE); + + hr_update_hotspare_svc_id(vol, hs, 0); + hr_update_hotspare_status(vol, hs, HR_EXT_INVALID); + + vol->hotspare_no--; + + if (faulty_svc_id != 0) + block_fini(faulty_svc_id); + + return EOK; +} + static errno_t hr_raid1_restore_blocks(hr_volume_t *vol, size_t rebuild_idx, uint64_t ba, size_t cnt, void *buf) { @@ -716,110 +778,51 @@ static errno_t hr_raid1_restore_blocks(hr_volume_t *vol, size_t rebuild_idx, return EOK; } -/* - * Put the last HOTSPARE extent in place - * of first that != ONLINE, and start the rebuild. - */ -static errno_t hr_raid1_rebuild(void *arg) +static void hr_process_deferred_invalidations(hr_volume_t *vol) { - HR_DEBUG("hr_raid1_rebuild()\n"); - - hr_volume_t *vol = arg; - void *buf = NULL; - size_t rebuild_idx; - errno_t rc; - - rc = init_rebuild(vol, &rebuild_idx); - if (rc != EOK) - return rc; - - size_t left = vol->data_blkno; - size_t max_blks = DATA_XFER_LIMIT / vol->bsize; - buf = malloc(max_blks * vol->bsize); - - size_t cnt; - uint64_t ba = 0; - hr_add_ba_offset(vol, &ba); - - fibril_rwlock_read_lock(&vol->extents_lock); + HR_DEBUG("hr_raid1_update_vol_status(): deferred invalidations\n"); - hr_range_lock_t *rl = NULL; + fibril_mutex_lock(&vol->halt_lock); + vol->halt_please = true; + fibril_rwlock_write_lock(&vol->extents_lock); + fibril_rwlock_write_lock(&vol->states_lock); + fibril_mutex_lock(&vol->hotspare_lock); - while (left != 0) { - if (vol->halt_please) { - fibril_rwlock_read_unlock(&vol->extents_lock); - fibril_mutex_lock(&vol->halt_lock); - fibril_mutex_unlock(&vol->halt_lock); - fibril_rwlock_read_lock(&vol->extents_lock); - } + list_foreach(vol->deferred_invalidations_list, link, + hr_deferred_invalidation_t, di) { + assert(vol->extents[di->index].status == HR_EXT_INVALID); - cnt = min(max_blks, left); + HR_DEBUG("moving invalidated extent no. %lu to hotspares\n", + di->index); - rl = hr_range_lock_acquire(vol, ba, cnt); - if (rl == NULL) { - rc = ENOMEM; - goto end; - } + block_fini(di->svc_id); - atomic_store_explicit(&vol->rebuild_blk, ba, - memory_order_relaxed); + size_t hs_idx = vol->hotspare_no; - rc = hr_raid1_restore_blocks(vol, rebuild_idx, ba, cnt, buf); + vol->hotspare_no++; - hr_range_lock_release(rl); + hr_update_hotspare_svc_id(vol, hs_idx, di->svc_id); + hr_update_hotspare_status(vol, hs_idx, HR_EXT_HOTSPARE); - if (rc != EOK) - goto end; + hr_update_ext_svc_id(vol, di->index, 0); + hr_update_ext_status(vol, di->index, HR_EXT_MISSING); - ba += cnt; - left -= cnt; + assert(vol->hotspare_no < HR_MAX_HOTSPARES + HR_MAX_EXTENTS); } - HR_DEBUG("hr_raid1_rebuild(): rebuild finished on \"%s\" (%lu), " - "extent no. %lu\n", vol->devname, vol->svc_id, rebuild_idx); - - fibril_rwlock_write_lock(&vol->states_lock); - - hr_update_ext_status(vol, rebuild_idx, HR_EXT_ONLINE); - /* - * We can be optimistic here, if some extents are - * still INVALID, FAULTY or MISSING, the update vol - * function will pick them up, and set the volume - * state accordingly. - */ - hr_update_vol_status(vol, HR_VOL_ONLINE); - atomic_store(&vol->state_changed, true); - - fibril_rwlock_write_unlock(&vol->states_lock); - - /* - * For now write metadata at the end, because - * we don't sync metada accross extents yet. - */ - hr_write_meta_to_ext(vol, rebuild_idx); -end: - if (rc != EOK) { - /* - * We can fail either because: - * - the rebuild extent failing or invalidation - * - there is are no ONLINE extents (vol is FAULTY) - * - we got ENOMEM on all READs (we also invalidate the - * rebuild extent here, for now) - */ - fibril_rwlock_write_lock(&vol->states_lock); - hr_update_vol_status(vol, HR_VOL_DEGRADED); - atomic_store(&vol->state_changed, true); - fibril_rwlock_write_unlock(&vol->states_lock); + for (size_t i = 0; i < HR_MAX_EXTENTS; i++) { + hr_deferred_invalidation_t *di = &vol->deferred_inval[i]; + if (di->svc_id != 0) { + list_remove(&di->link); + di->svc_id = 0; + } } - fibril_rwlock_read_unlock(&vol->extents_lock); - - hr_raid1_update_vol_status(vol); - - if (buf != NULL) - free(buf); - - return rc; + fibril_mutex_unlock(&vol->hotspare_lock); + fibril_rwlock_write_unlock(&vol->states_lock); + fibril_rwlock_write_unlock(&vol->extents_lock); + vol->halt_please = false; + fibril_mutex_unlock(&vol->halt_lock); } /** @} From 23df41bf64b8d1ae27e3d8f487225995d26bffc8 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 13 Jan 2025 23:18:22 +0100 Subject: [PATCH 130/324] hr: move hr_process_deferred_invalidations() to util --- uspace/srv/bd/hr/raid1.c | 56 +++++----------------------------------- uspace/srv/bd/hr/util.c | 47 +++++++++++++++++++++++++++++++++ uspace/srv/bd/hr/util.h | 1 + 3 files changed, 54 insertions(+), 50 deletions(-) diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 4e080076db..0b5f7c2806 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -66,7 +66,6 @@ static errno_t init_rebuild(hr_volume_t *, size_t *); static errno_t swap_hs(hr_volume_t *, size_t, size_t); static errno_t hr_raid1_restore_blocks(hr_volume_t *, size_t, uint64_t, size_t, void *); -static void hr_process_deferred_invalidations(hr_volume_t *); /* bdops */ static errno_t hr_raid1_bd_open(bd_srvs_t *, bd_srv_t *); @@ -107,7 +106,11 @@ errno_t hr_raid1_create(hr_volume_t *new_volume) /* force volume state update */ atomic_store(&new_volume->state_changed, true); hr_raid1_update_vol_status(new_volume); - if (new_volume->status == HR_VOL_FAULTY) + + fibril_rwlock_read_lock(&new_volume->states_lock); + hr_vol_status_t state = new_volume->status; + fibril_rwlock_read_unlock(&new_volume->states_lock); + if (state == HR_VOL_FAULTY || state == HR_VOL_INVALID) return EINVAL; rc = hr_register_volume(new_volume); @@ -358,7 +361,7 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, hr_vol_status_t vol_state = vol->status; fibril_rwlock_read_unlock(&vol->states_lock); - if (vol_state == HR_VOL_FAULTY) + if (vol_state == HR_VOL_FAULTY || vol_state == HR_VOL_INVALID) return EIO; if (type == HR_BD_READ || type == HR_BD_WRITE) @@ -778,52 +781,5 @@ static errno_t hr_raid1_restore_blocks(hr_volume_t *vol, size_t rebuild_idx, return EOK; } -static void hr_process_deferred_invalidations(hr_volume_t *vol) -{ - HR_DEBUG("hr_raid1_update_vol_status(): deferred invalidations\n"); - - fibril_mutex_lock(&vol->halt_lock); - vol->halt_please = true; - fibril_rwlock_write_lock(&vol->extents_lock); - fibril_rwlock_write_lock(&vol->states_lock); - fibril_mutex_lock(&vol->hotspare_lock); - - list_foreach(vol->deferred_invalidations_list, link, - hr_deferred_invalidation_t, di) { - assert(vol->extents[di->index].status == HR_EXT_INVALID); - - HR_DEBUG("moving invalidated extent no. %lu to hotspares\n", - di->index); - - block_fini(di->svc_id); - - size_t hs_idx = vol->hotspare_no; - - vol->hotspare_no++; - - hr_update_hotspare_svc_id(vol, hs_idx, di->svc_id); - hr_update_hotspare_status(vol, hs_idx, HR_EXT_HOTSPARE); - - hr_update_ext_svc_id(vol, di->index, 0); - hr_update_ext_status(vol, di->index, HR_EXT_MISSING); - - assert(vol->hotspare_no < HR_MAX_HOTSPARES + HR_MAX_EXTENTS); - } - - for (size_t i = 0; i < HR_MAX_EXTENTS; i++) { - hr_deferred_invalidation_t *di = &vol->deferred_inval[i]; - if (di->svc_id != 0) { - list_remove(&di->link); - di->svc_id = 0; - } - } - - fibril_mutex_unlock(&vol->hotspare_lock); - fibril_rwlock_write_unlock(&vol->states_lock); - fibril_rwlock_write_unlock(&vol->extents_lock); - vol->halt_please = false; - fibril_mutex_unlock(&vol->halt_lock); -} - /** @} */ diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index fbfef6362a..9ee5763ee5 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -409,5 +409,52 @@ static bool hr_range_lock_overlap(hr_range_lock_t *rl1, hr_range_lock_t *rl2) return true; } +void hr_process_deferred_invalidations(hr_volume_t *vol) +{ + HR_DEBUG("hr_raid1_update_vol_status(): deferred invalidations\n"); + + fibril_mutex_lock(&vol->halt_lock); + vol->halt_please = true; + fibril_rwlock_write_lock(&vol->extents_lock); + fibril_rwlock_write_lock(&vol->states_lock); + fibril_mutex_lock(&vol->hotspare_lock); + + list_foreach(vol->deferred_invalidations_list, link, + hr_deferred_invalidation_t, di) { + assert(vol->extents[di->index].status == HR_EXT_INVALID); + + HR_DEBUG("moving invalidated extent no. %lu to hotspares\n", + di->index); + + block_fini(di->svc_id); + + size_t hs_idx = vol->hotspare_no; + + vol->hotspare_no++; + + hr_update_hotspare_svc_id(vol, hs_idx, di->svc_id); + hr_update_hotspare_status(vol, hs_idx, HR_EXT_HOTSPARE); + + hr_update_ext_svc_id(vol, di->index, 0); + hr_update_ext_status(vol, di->index, HR_EXT_MISSING); + + assert(vol->hotspare_no < HR_MAX_HOTSPARES + HR_MAX_EXTENTS); + } + + for (size_t i = 0; i < HR_MAX_EXTENTS; i++) { + hr_deferred_invalidation_t *di = &vol->deferred_inval[i]; + if (di->svc_id != 0) { + list_remove(&di->link); + di->svc_id = 0; + } + } + + fibril_mutex_unlock(&vol->hotspare_lock); + fibril_rwlock_write_unlock(&vol->states_lock); + fibril_rwlock_write_unlock(&vol->extents_lock); + vol->halt_please = false; + fibril_mutex_unlock(&vol->halt_lock); +} + /** @} */ diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index 7489afc0e7..256b9a3d70 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -66,6 +66,7 @@ extern size_t hr_count_extents(hr_volume_t *, hr_ext_status_t); extern hr_range_lock_t *hr_range_lock_acquire(hr_volume_t *, uint64_t, uint64_t); extern void hr_range_lock_release(hr_range_lock_t *rl); +extern void hr_process_deferred_invalidations(hr_volume_t *); #endif From a6fb9376fa4eccaea6516946b1349c09335ef310 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 14 Jan 2025 23:26:11 +0100 Subject: [PATCH 131/324] hr: RAID0: handle hr_fgroup_create() -> ENOMEM --- uspace/srv/bd/hr/raid0.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index 265e860660..c01c75b7f4 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -242,6 +242,8 @@ static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, if (type == HR_BD_SYNC && ba == 0 && cnt == 0) { hr_fgroup_t *group = hr_fgroup_create(vol->fge, vol->extent_no); + if (group == NULL) + return ENOMEM; for (size_t i = 0; i < vol->extent_no; i++) { hr_io_t *io = hr_fgroup_alloc(group); @@ -287,6 +289,8 @@ static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, size_t span = end_strip_no - strip_no + 1; hr_fgroup_t *group = hr_fgroup_create(vol->fge, span); + if (group == NULL) + return ENOMEM; while (left != 0) { phys_block = stripe * strip_size + strip_off; From 9f15da1bc02d6b204be313a1342ba1e4474ffb03 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 14 Jan 2025 23:28:16 +0100 Subject: [PATCH 132/324] hr: fge: fix fibril unsafe assert --- uspace/srv/bd/hr/fge.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uspace/srv/bd/hr/fge.c b/uspace/srv/bd/hr/fge.c index 0d50686a06..30652ded11 100644 --- a/uspace/srv/bd/hr/fge.c +++ b/uspace/srv/bd/hr/fge.c @@ -300,9 +300,9 @@ void hr_fgroup_submit(hr_fgroup_t *group, hr_wu_t wu, void *arg) errno_t hr_fgroup_wait(hr_fgroup_t *group, size_t *rokay, size_t *rfailed) { + fibril_mutex_lock(&group->lock); assert(group->submitted == group->wu_cnt); - fibril_mutex_lock(&group->lock); while (true) { size_t finished = group->finished_fail + group->finished_okay; if (group->wu_cnt == finished) From 7debda3acff62022af257dcb0207a1ccc5a6adda Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Wed, 22 Jan 2025 21:11:06 +0100 Subject: [PATCH 133/324] hr: fge: make group->wu_cnt an upper bound --- uspace/srv/bd/hr/fge.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/uspace/srv/bd/hr/fge.c b/uspace/srv/bd/hr/fge.c index 30652ded11..af23f140c9 100644 --- a/uspace/srv/bd/hr/fge.c +++ b/uspace/srv/bd/hr/fge.c @@ -301,11 +301,11 @@ void hr_fgroup_submit(hr_fgroup_t *group, hr_wu_t wu, void *arg) errno_t hr_fgroup_wait(hr_fgroup_t *group, size_t *rokay, size_t *rfailed) { fibril_mutex_lock(&group->lock); - assert(group->submitted == group->wu_cnt); + assert(group->submitted <= group->wu_cnt); while (true) { size_t finished = group->finished_fail + group->finished_okay; - if (group->wu_cnt == finished) + if (finished == group->submitted) break; fibril_condvar_wait(&group->all_done, &group->lock); @@ -403,9 +403,9 @@ static errno_t fge_fibril(void *arg) fibril_mutex_lock(&group->lock); size_t finished = group->finished_fail + group->finished_okay; - fibril_mutex_unlock(&group->lock); - if (finished == group->wu_cnt) + if (finished == group->submitted) fibril_condvar_signal(&group->all_done); + fibril_mutex_unlock(&group->lock); fibril_mutex_unlock(&pool->lock); } From 8cdf360b980d6b74b10bbef344f15954d543d30e Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Wed, 5 Mar 2025 09:52:17 +0100 Subject: [PATCH 134/324] app/hrctl: fix case for 'n' --- uspace/app/hrctl/hrctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index 9ab87669b8..3316f4c96d 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -345,7 +345,7 @@ int main(int argc, char **argv) free(cfg); return 1; } - break; + goto skip; case 'H': if (optind != 3 && argc != 4) goto bad; From 0fcb011fb7aea6151e2507840349464ffd68ec2b Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Wed, 5 Mar 2025 10:32:22 +0100 Subject: [PATCH 135/324] hr: raid0.c: early break if (left == 0) --- uspace/srv/bd/hr/raid0.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index c01c75b7f4..07fd6fc267 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -310,12 +310,15 @@ static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, hr_fgroup_submit(group, hr_io_worker, io); + left -= cnt; + if (left == 0) + break; + if (type == HR_BD_READ) data_read += len; else if (type == HR_BD_WRITE) data_write += len; - left -= cnt; strip_off = 0; extent++; if (extent >= vol->extent_no) { From b15e53441c58425537dfcd0730ac30c4e7e74d0d Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Thu, 6 Mar 2025 19:16:31 +0100 Subject: [PATCH 136/324] hr/fge.c: add some comments --- uspace/srv/bd/hr/fge.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/uspace/srv/bd/hr/fge.c b/uspace/srv/bd/hr/fge.c index af23f140c9..aae010d4ed 100644 --- a/uspace/srv/bd/hr/fge.c +++ b/uspace/srv/bd/hr/fge.c @@ -114,6 +114,7 @@ struct hr_fgroup { hr_fpool_t *hr_fpool_create(size_t fibril_cnt, size_t max_wus, size_t wu_storage_size) { + /* TODO: allow wu_storage_size to be 0 (we want to save mem) */ assert(max_wus > 0 && wu_storage_size > 0); void *bitmap_data = NULL; @@ -188,6 +189,13 @@ hr_fgroup_t *hr_fgroup_create(hr_fpool_t *parent, size_t wu_cnt) { assert(wu_cnt > 0); + /* + * XXX: we can also get rid of this malloc() call, + * somewhat... + * + * Have some fgroups also pre-allocated for maximum + * pre-allocation power :-) + */ hr_fgroup_t *result = malloc(sizeof(hr_fgroup_t)); if (result == NULL) return NULL; From 4d30c4753e7a8a1af1d946fc6a949460b2e04ce1 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Thu, 6 Mar 2025 20:40:24 +0100 Subject: [PATCH 137/324] hr: raid1.c: fix rebuild --- uspace/srv/bd/hr/raid1.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 0b5f7c2806..dc790f6514 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -532,18 +532,15 @@ static errno_t hr_raid1_rebuild(void *arg) uint64_t ba = 0; hr_add_ba_offset(vol, &ba); + /* + * XXX: this is useless here after simplified DI, because + * rebuild cannot be triggered while ongoing rebuild + */ fibril_rwlock_read_lock(&vol->extents_lock); hr_range_lock_t *rl = NULL; while (left != 0) { - if (vol->halt_please) { - fibril_rwlock_read_unlock(&vol->extents_lock); - fibril_mutex_lock(&vol->halt_lock); - fibril_mutex_unlock(&vol->halt_lock); - fibril_rwlock_read_lock(&vol->extents_lock); - } - cnt = min(max_blks, left); rl = hr_range_lock_acquire(vol, ba, cnt); @@ -572,6 +569,7 @@ static errno_t hr_raid1_rebuild(void *arg) fibril_rwlock_write_lock(&vol->states_lock); hr_update_ext_status(vol, rebuild_idx, HR_EXT_ONLINE); + /* * We can be optimistic here, if some extents are * still INVALID, FAULTY or MISSING, the update vol @@ -722,13 +720,20 @@ static errno_t hr_raid1_restore_blocks(hr_volume_t *vol, size_t rebuild_idx, errno_t rc = ENOENT; hr_extent_t *ext, *rebuild_ext = &vol->extents[rebuild_idx]; + fibril_rwlock_read_lock(&vol->states_lock); + hr_ext_status_t rebuild_ext_status = rebuild_ext->status; + fibril_rwlock_read_unlock(&vol->states_lock); + + if (rebuild_ext_status != HR_EXT_REBUILD) + return EINVAL; + for (size_t i = 0; i < vol->extent_no; i++) { fibril_rwlock_read_lock(&vol->states_lock); - ext = &vol->extents[i]; - if (ext->status != HR_EXT_ONLINE) + if (ext->status != HR_EXT_ONLINE) { + fibril_rwlock_read_unlock(&vol->states_lock); continue; - + } fibril_rwlock_read_unlock(&vol->states_lock); rc = block_read_direct(ext->svc_id, ba, cnt, buf); From 612375389d7150b4101894ae3577547e4b1bf9a9 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Thu, 6 Mar 2025 20:42:14 +0100 Subject: [PATCH 138/324] hr: raid1.c: print rebuild progress every 5% --- uspace/srv/bd/hr/raid1.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index dc790f6514..fe71a93d33 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -540,6 +540,7 @@ static errno_t hr_raid1_rebuild(void *arg) hr_range_lock_t *rl = NULL; + unsigned int percent, old_percent = 100; while (left != 0) { cnt = min(max_blks, left); @@ -554,6 +555,13 @@ static errno_t hr_raid1_rebuild(void *arg) rc = hr_raid1_restore_blocks(vol, rebuild_idx, ba, cnt, buf); + percent = ((ba + cnt) * 100) / vol->data_blkno; + if (percent != old_percent) { + if (percent % 5 == 0) + HR_DEBUG("\"%s\" REBUILD progress: %u%%\n", + vol->devname, percent); + } + hr_range_lock_release(rl); if (rc != EOK) @@ -561,6 +569,7 @@ static errno_t hr_raid1_rebuild(void *arg) ba += cnt; left -= cnt; + old_percent = percent; } HR_DEBUG("hr_raid1_rebuild(): rebuild finished on \"%s\" (%lu), " @@ -713,8 +722,6 @@ static errno_t swap_hs(hr_volume_t *vol, size_t bad, size_t hs) static errno_t hr_raid1_restore_blocks(hr_volume_t *vol, size_t rebuild_idx, uint64_t ba, size_t cnt, void *buf) { - HR_DEBUG("REBUILD restoring blocks (ba: %lu, cnt: %lu)\n", ba, cnt); - assert(fibril_rwlock_is_locked(&vol->extents_lock)); errno_t rc = ENOENT; From 4d42a1b16391284c1957951c186c1e20f58fa93b Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Thu, 6 Mar 2025 21:13:11 +0100 Subject: [PATCH 139/324] hr: remove deferred invalidations --- uspace/srv/bd/hr/hr.c | 4 ---- uspace/srv/bd/hr/raid1.c | 34 ----------------------------- uspace/srv/bd/hr/util.c | 47 ---------------------------------------- uspace/srv/bd/hr/util.h | 1 - uspace/srv/bd/hr/var.h | 12 ---------- 5 files changed, 98 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index e2c12c3c34..f5901d137a 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -259,12 +259,8 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) list_initialize(&new_volume->range_lock_list); fibril_mutex_initialize(&new_volume->range_lock_list_lock); - fibril_mutex_initialize(&new_volume->deferred_list_lock); - list_initialize(&new_volume->deferred_invalidations_list); - atomic_init(&new_volume->rebuild_blk, 0); atomic_init(&new_volume->state_changed, false); - atomic_init(&new_volume->pending_invalidation, false); rc = new_volume->hr_ops.create(new_volume); if (rc != EOK) diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index fe71a93d33..10a4893a84 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -227,13 +227,6 @@ static void hr_raid1_update_vol_status(hr_volume_t *vol) if (!atomic_compare_exchange_strong(&vol->state_changed, &exp, false)) return; - if (atomic_compare_exchange_strong(&vol->pending_invalidation, &exp, - false)) { - fibril_mutex_lock(&vol->deferred_list_lock); - hr_process_deferred_invalidations(vol); - fibril_mutex_unlock(&vol->deferred_list_lock); - } - fibril_rwlock_read_lock(&vol->extents_lock); fibril_rwlock_read_lock(&vol->states_lock); @@ -288,34 +281,7 @@ static void hr_raid1_ext_state_callback(hr_volume_t *vol, size_t extent, switch (rc) { case ENOMEM: - fibril_mutex_lock(&vol->deferred_list_lock); - - service_id_t invalid_svc_id = vol->extents[extent].svc_id; - - list_foreach(vol->deferred_invalidations_list, link, - hr_deferred_invalidation_t, di) { - if (di->svc_id == invalid_svc_id) { - assert(vol->extents[extent].status == - HR_EXT_INVALID); - goto deferring_end; - } - } - - assert(vol->extents[extent].svc_id != HR_EXT_INVALID); - hr_update_ext_status(vol, extent, HR_EXT_INVALID); - - size_t i = list_count(&vol->deferred_invalidations_list); - vol->deferred_inval[i].svc_id = invalid_svc_id; - vol->deferred_inval[i].index = extent; - - list_append(&vol->deferred_inval[i].link, - &vol->deferred_invalidations_list); - - atomic_store(&vol->pending_invalidation, true); - deferring_end: - - fibril_mutex_unlock(&vol->deferred_list_lock); break; case ENOENT: hr_update_ext_status(vol, extent, HR_EXT_MISSING); diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 9ee5763ee5..fbfef6362a 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -409,52 +409,5 @@ static bool hr_range_lock_overlap(hr_range_lock_t *rl1, hr_range_lock_t *rl2) return true; } -void hr_process_deferred_invalidations(hr_volume_t *vol) -{ - HR_DEBUG("hr_raid1_update_vol_status(): deferred invalidations\n"); - - fibril_mutex_lock(&vol->halt_lock); - vol->halt_please = true; - fibril_rwlock_write_lock(&vol->extents_lock); - fibril_rwlock_write_lock(&vol->states_lock); - fibril_mutex_lock(&vol->hotspare_lock); - - list_foreach(vol->deferred_invalidations_list, link, - hr_deferred_invalidation_t, di) { - assert(vol->extents[di->index].status == HR_EXT_INVALID); - - HR_DEBUG("moving invalidated extent no. %lu to hotspares\n", - di->index); - - block_fini(di->svc_id); - - size_t hs_idx = vol->hotspare_no; - - vol->hotspare_no++; - - hr_update_hotspare_svc_id(vol, hs_idx, di->svc_id); - hr_update_hotspare_status(vol, hs_idx, HR_EXT_HOTSPARE); - - hr_update_ext_svc_id(vol, di->index, 0); - hr_update_ext_status(vol, di->index, HR_EXT_MISSING); - - assert(vol->hotspare_no < HR_MAX_HOTSPARES + HR_MAX_EXTENTS); - } - - for (size_t i = 0; i < HR_MAX_EXTENTS; i++) { - hr_deferred_invalidation_t *di = &vol->deferred_inval[i]; - if (di->svc_id != 0) { - list_remove(&di->link); - di->svc_id = 0; - } - } - - fibril_mutex_unlock(&vol->hotspare_lock); - fibril_rwlock_write_unlock(&vol->states_lock); - fibril_rwlock_write_unlock(&vol->extents_lock); - vol->halt_please = false; - fibril_mutex_unlock(&vol->halt_lock); -} - /** @} */ diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index 256b9a3d70..7489afc0e7 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -66,7 +66,6 @@ extern size_t hr_count_extents(hr_volume_t *, hr_ext_status_t); extern hr_range_lock_t *hr_range_lock_acquire(hr_volume_t *, uint64_t, uint64_t); extern void hr_range_lock_release(hr_range_lock_t *rl); -extern void hr_process_deferred_invalidations(hr_volume_t *); #endif diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index ee65adf664..98a27d706f 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -109,18 +109,6 @@ typedef struct hr_volume { bool halt_please; fibril_mutex_t halt_lock; - /* - * For deferring invalidations of extents. Used when - * an extent has to be invalidated (got ENOMEM on a WRITE), - * but workers - therefore state callbacks cannot lock - * extents for writing (they are readers), so invalidations - * are harvested later when we are able to. - */ - _Atomic bool pending_invalidation; - fibril_mutex_t deferred_list_lock; - list_t deferred_invalidations_list; - hr_deferred_invalidation_t deferred_inval[HR_MAX_EXTENTS]; - _Atomic bool state_changed; _Atomic uint64_t rebuild_blk; uint64_t counter; /* metadata syncing */ From 10005fd097a58d8ce2732782aaa4e93997bc8d52 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Thu, 6 Mar 2025 21:13:51 +0100 Subject: [PATCH 140/324] hr: remove vol->halt_please bit and vol->halt_lock RW locks are not write-starved now --- uspace/srv/bd/hr/hr.c | 3 --- uspace/srv/bd/hr/raid1.c | 15 --------------- uspace/srv/bd/hr/var.h | 4 ---- 3 files changed, 22 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index f5901d137a..1b4f8f505a 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -248,9 +248,6 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) fibril_mutex_initialize(&new_volume->lock); /* XXX: will remove this */ - fibril_mutex_initialize(&new_volume->halt_lock); - new_volume->halt_please = false; - fibril_rwlock_initialize(&new_volume->extents_lock); fibril_rwlock_initialize(&new_volume->states_lock); diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 10a4893a84..97eb543c17 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -342,17 +342,6 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, if (type != HR_BD_SYNC || ba != 0) hr_add_ba_offset(vol, &ba); - /* - * this is to allow adding hotspare or start a rebuild on - * very busy array, because of how rwlocks are implemented - * in HelenOS (no writer priority, so if there are multiple - * continuos readers, writer will never own the lock) - */ - if (vol->halt_please) { - fibril_mutex_lock(&vol->halt_lock); - fibril_mutex_unlock(&vol->halt_lock); - } - /* * extent order has to be locked for the whole IO duration, * so that workers have consistent targets @@ -590,8 +579,6 @@ static errno_t init_rebuild(hr_volume_t *vol, size_t *rebuild_idx) { errno_t rc = EOK; - fibril_mutex_lock(&vol->halt_lock); - vol->halt_please = true; fibril_rwlock_write_lock(&vol->extents_lock); fibril_rwlock_write_lock(&vol->states_lock); fibril_mutex_lock(&vol->hotspare_lock); @@ -650,8 +637,6 @@ static errno_t init_rebuild(hr_volume_t *vol, size_t *rebuild_idx) fibril_mutex_unlock(&vol->hotspare_lock); fibril_rwlock_write_unlock(&vol->states_lock); fibril_rwlock_write_unlock(&vol->extents_lock); - vol->halt_please = false; - fibril_mutex_unlock(&vol->halt_lock); return rc; } diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index 98a27d706f..a861058694 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -105,10 +105,6 @@ typedef struct hr_volume { /* protects states (extents.status, hr_volume_t.status) */ fibril_rwlock_t states_lock; - /* for halting IO requests when a REBUILD start waits */ - bool halt_please; - fibril_mutex_t halt_lock; - _Atomic bool state_changed; _Atomic uint64_t rebuild_blk; uint64_t counter; /* metadata syncing */ From d6fe2a1a254fa576538892960e5ea16d7bb73a77 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Thu, 6 Mar 2025 21:42:44 +0100 Subject: [PATCH 141/324] hr: hr_mark_vol_state_dirty() helper --- uspace/srv/bd/hr/hr.c | 2 +- uspace/srv/bd/hr/raid1.c | 10 +++++----- uspace/srv/bd/hr/util.c | 6 ++++++ uspace/srv/bd/hr/util.h | 3 ++- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 1b4f8f505a..a2777ffcce 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -317,7 +317,7 @@ static void hr_stop_srv(ipc_call_t *icall) /* TODO: maybe expose extent state callbacks */ hr_update_ext_status(vol, fail_extent, HR_EXT_FAILED); - atomic_store(&vol->state_changed, true); + hr_mark_vol_state_dirty(vol); fibril_rwlock_read_unlock(&vol->extents_lock); fibril_rwlock_write_unlock(&vol->states_lock); diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 97eb543c17..988d0ed757 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -104,7 +104,7 @@ errno_t hr_raid1_create(hr_volume_t *new_volume) new_volume->hr_bds.sarg = new_volume; /* force volume state update */ - atomic_store(&new_volume->state_changed, true); + hr_mark_vol_state_dirty(new_volume); hr_raid1_update_vol_status(new_volume); fibril_rwlock_read_lock(&new_volume->states_lock); @@ -166,7 +166,7 @@ errno_t hr_raid1_add_hotspare(hr_volume_t *vol, service_id_t hotspare) hr_update_hotspare_svc_id(vol, hs_idx, hotspare); hr_update_hotspare_status(vol, hs_idx, HR_EXT_HOTSPARE); - atomic_store(&vol->state_changed, true); + hr_mark_vol_state_dirty(vol); error: fibril_mutex_unlock(&vol->hotspare_lock); @@ -290,7 +290,7 @@ static void hr_raid1_ext_state_callback(hr_volume_t *vol, size_t extent, hr_update_ext_status(vol, extent, HR_EXT_FAILED); } - atomic_store(&vol->state_changed, true); + hr_mark_vol_state_dirty(vol); fibril_rwlock_write_unlock(&vol->states_lock); } @@ -541,7 +541,7 @@ static errno_t hr_raid1_rebuild(void *arg) * state accordingly. */ hr_update_vol_status(vol, HR_VOL_ONLINE); - atomic_store(&vol->state_changed, true); + hr_mark_vol_state_dirty(vol); fibril_rwlock_write_unlock(&vol->states_lock); @@ -561,7 +561,7 @@ static errno_t hr_raid1_rebuild(void *arg) */ fibril_rwlock_write_lock(&vol->states_lock); hr_update_vol_status(vol, HR_VOL_DEGRADED); - atomic_store(&vol->state_changed, true); + hr_mark_vol_state_dirty(vol); fibril_rwlock_write_unlock(&vol->states_lock); } diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index fbfef6362a..f01d581142 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -409,5 +410,10 @@ static bool hr_range_lock_overlap(hr_range_lock_t *rl1, hr_range_lock_t *rl2) return true; } +void hr_mark_vol_state_dirty(hr_volume_t *vol) +{ + atomic_store(&vol->state_changed, true); +} + /** @} */ diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index 7489afc0e7..46294ff392 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -65,7 +65,8 @@ extern void hr_sync_all_extents(hr_volume_t *); extern size_t hr_count_extents(hr_volume_t *, hr_ext_status_t); extern hr_range_lock_t *hr_range_lock_acquire(hr_volume_t *, uint64_t, uint64_t); -extern void hr_range_lock_release(hr_range_lock_t *rl); +extern void hr_range_lock_release(hr_range_lock_t *); +extern void hr_mark_vol_state_dirty(hr_volume_t *); #endif From f1be66bf66ac82676d5a20f271776de58afafac5 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Thu, 6 Mar 2025 22:47:13 +0100 Subject: [PATCH 142/324] hr: raid5.c: fast patch to make new asserts pass --- uspace/srv/bd/hr/raid5.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 7b22322470..b8112db0dc 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -101,9 +101,13 @@ errno_t hr_raid5_create(hr_volume_t *new_volume) return EINVAL; } + fibril_rwlock_write_lock(&new_volume->states_lock); + rc = hr_raid5_update_vol_status(new_volume); - if (rc != EOK) + if (rc != EOK) { + fibril_rwlock_write_unlock(&new_volume->states_lock); return rc; + } bd_srvs_init(&new_volume->hr_bds); new_volume->hr_bds.ops = &hr_raid5_bd_ops; @@ -111,6 +115,8 @@ errno_t hr_raid5_create(hr_volume_t *new_volume) rc = hr_register_volume(new_volume); + fibril_rwlock_write_unlock(&new_volume->states_lock); + return rc; } @@ -139,7 +145,9 @@ errno_t hr_raid5_init(hr_volume_t *vol) void hr_raid5_status_event(hr_volume_t *vol) { fibril_mutex_lock(&vol->lock); + fibril_rwlock_write_lock(&vol->states_lock); (void)hr_raid5_update_vol_status(vol); + fibril_rwlock_write_unlock(&vol->states_lock); fibril_mutex_unlock(&vol->lock); } @@ -148,6 +156,7 @@ errno_t hr_raid5_add_hotspare(hr_volume_t *vol, service_id_t hotspare) HR_DEBUG("hr_raid5_add_hotspare()\n"); fibril_mutex_lock(&vol->lock); + fibril_mutex_lock(&vol->hotspare_lock); if (vol->hotspare_no >= HR_MAX_HOTSPARES) { HR_ERROR("hr_raid5_add_hotspare(): cannot add more hotspares " @@ -157,10 +166,11 @@ errno_t hr_raid5_add_hotspare(hr_volume_t *vol, service_id_t hotspare) } vol->hotspares[vol->hotspare_no].svc_id = hotspare; - hr_update_hotspare_status(vol, vol->hotspare_no, HR_EXT_HOTSPARE); vol->hotspare_no++; + hr_update_hotspare_status(vol, vol->hotspare_no - 1, HR_EXT_HOTSPARE); + /* * If the volume is degraded, start rebuild right away. */ @@ -168,12 +178,16 @@ errno_t hr_raid5_add_hotspare(hr_volume_t *vol, service_id_t hotspare) HR_DEBUG("hr_raid5_add_hotspare(): volume in DEGRADED state, " "spawning new rebuild fibril\n"); fid_t fib = fibril_create(hr_raid5_rebuild, vol); - if (fib == 0) + if (fib == 0) { + fibril_mutex_unlock(&vol->hotspare_lock); + fibril_mutex_unlock(&vol->lock); return ENOMEM; + } fibril_start(fib); fibril_detach(fib); } + fibril_mutex_unlock(&vol->hotspare_lock); fibril_mutex_unlock(&vol->lock); return EOK; @@ -586,6 +600,7 @@ static errno_t hr_raid5_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, left = cnt; + fibril_rwlock_write_lock(&vol->states_lock); while (left != 0) { phys_block = ext_stripe * strip_size + strip_off; cnt = min(left, strip_size - strip_off); @@ -683,6 +698,7 @@ static errno_t hr_raid5_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, error: (void)hr_raid5_update_vol_status(vol); + fibril_rwlock_write_unlock(&vol->states_lock); fibril_mutex_unlock(&vol->lock); return rc; } @@ -696,6 +712,8 @@ static errno_t hr_raid5_rebuild(void *arg) void *buf = NULL, *xorbuf = NULL; fibril_mutex_lock(&vol->lock); + fibril_rwlock_read_lock(&vol->extents_lock); + fibril_rwlock_write_lock(&vol->states_lock); if (vol->hotspare_no == 0) { HR_WARN("hr_raid5_rebuild(): no free hotspares on \"%s\", " @@ -737,7 +755,9 @@ static errno_t hr_raid5_rebuild(void *arg) hr_update_ext_status(vol, bad, HR_EXT_HOTSPARE); vol->hotspares[hotspare_idx].svc_id = 0; + fibril_mutex_lock(&vol->hotspare_lock); hr_update_hotspare_status(vol, hotspare_idx, HR_EXT_MISSING); + fibril_mutex_unlock(&vol->hotspare_lock); vol->hotspare_no--; @@ -812,8 +832,10 @@ static errno_t hr_raid5_rebuild(void *arg) * Let other IO requests be served * during rebuild. */ + fibril_rwlock_write_unlock(&vol->states_lock); fibril_mutex_unlock(&vol->lock); fibril_mutex_lock(&vol->lock); + fibril_rwlock_write_lock(&vol->states_lock); } HR_DEBUG("hr_raid5_rebuild(): rebuild finished on \"%s\" (%lu), " @@ -828,6 +850,8 @@ static errno_t hr_raid5_rebuild(void *arg) end: (void)hr_raid5_update_vol_status(vol); + fibril_rwlock_write_unlock(&vol->states_lock); + fibril_rwlock_read_unlock(&vol->extents_lock); fibril_mutex_unlock(&vol->lock); if (buf != NULL) From d2da1be2df26d9abd2e8ef253d8ca5ce11175e9c Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 7 Mar 2025 00:12:28 +0100 Subject: [PATCH 143/324] hr: rename vol->state_changed -> vol->state_dirty --- uspace/srv/bd/hr/hr.c | 2 +- uspace/srv/bd/hr/raid1.c | 3 ++- uspace/srv/bd/hr/util.c | 2 +- uspace/srv/bd/hr/var.h | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index a2777ffcce..25c6b75864 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -257,7 +257,7 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) fibril_mutex_initialize(&new_volume->range_lock_list_lock); atomic_init(&new_volume->rebuild_blk, 0); - atomic_init(&new_volume->state_changed, false); + atomic_init(&new_volume->state_dirty, false); rc = new_volume->hr_ops.create(new_volume); if (rc != EOK) diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 988d0ed757..6934fe9e0f 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -224,7 +224,8 @@ static void hr_raid1_update_vol_status(hr_volume_t *vol) { bool exp = true; - if (!atomic_compare_exchange_strong(&vol->state_changed, &exp, false)) + /* TODO: could also wrap this */ + if (!atomic_compare_exchange_strong(&vol->state_dirty, &exp, false)) return; fibril_rwlock_read_lock(&vol->extents_lock); diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index f01d581142..e9e2640660 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -412,7 +412,7 @@ static bool hr_range_lock_overlap(hr_range_lock_t *rl1, hr_range_lock_t *rl2) void hr_mark_vol_state_dirty(hr_volume_t *vol) { - atomic_store(&vol->state_changed, true); + atomic_store(&vol->state_dirty, true); } /** @} diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index a861058694..d5185962aa 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -105,7 +105,7 @@ typedef struct hr_volume { /* protects states (extents.status, hr_volume_t.status) */ fibril_rwlock_t states_lock; - _Atomic bool state_changed; + _Atomic bool state_dirty; _Atomic uint64_t rebuild_blk; uint64_t counter; /* metadata syncing */ hr_vol_status_t status; From e24c0644b4afaab34c774cd347337ef8bf224e8b Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 7 Mar 2025 21:53:54 +0100 Subject: [PATCH 144/324] hr: add NONE state (use INVALID for inconsistent) --- uspace/lib/device/include/hr.h | 17 +++++++++-------- uspace/lib/device/src/hr.c | 16 +++++++++------- uspace/srv/bd/hr/raid1.c | 6 +++--- 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index 85b9ae56a0..43d730688d 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -67,17 +67,18 @@ typedef enum hr_level { #define HR_RLQ_RAID5_NC 0x03 /* RAID-5 Rotating Parity N with Data Continuation */ typedef enum hr_vol_status { - HR_VOL_INVALID, - HR_VOL_ONLINE, /* OPTIMAL */ - HR_VOL_FAULTY, - HR_VOL_DEGRADED, /* also used for partial, but usable mirror */ - HR_VOL_REBUILD + HR_VOL_NONE = 0, /* Unknown/None */ + HR_VOL_ONLINE, /* optimal */ + HR_VOL_FAULTY, /* unusable */ + HR_VOL_DEGRADED, /* not optimal */ + HR_VOL_REBUILD /* rebuild in progress */ } hr_vol_status_t; typedef enum hr_ext_status { - HR_EXT_INVALID, - HR_EXT_ONLINE, /* OK */ - HR_EXT_MISSING, + HR_EXT_NONE = 0, /* unknown/none status */ + HR_EXT_INVALID, /* working but not consistent */ + HR_EXT_ONLINE, /* ok */ + HR_EXT_MISSING, /* offline */ HR_EXT_FAILED, HR_EXT_REBUILD, HR_EXT_HOTSPARE diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index a9cf859403..7f44120ace 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -320,8 +320,8 @@ errno_t hr_print_status(void) const char *hr_get_vol_status_msg(hr_vol_status_t status) { switch (status) { - case HR_VOL_INVALID: - return "INVALID"; + case HR_VOL_NONE: + return "NONE/UNKNOWN"; case HR_VOL_ONLINE: return "ONLINE"; case HR_VOL_FAULTY: @@ -331,13 +331,15 @@ const char *hr_get_vol_status_msg(hr_vol_status_t status) case HR_VOL_REBUILD: return "REBUILD"; default: - return "UNKNOWN"; + return "Invalid state value"; } } const char *hr_get_ext_status_msg(hr_ext_status_t status) { switch (status) { + case HR_EXT_NONE: + return "NONE/UNKNOWN"; case HR_EXT_INVALID: return "INVALID"; case HR_EXT_ONLINE: @@ -351,7 +353,7 @@ const char *hr_get_ext_status_msg(hr_ext_status_t status) case HR_EXT_HOTSPARE: return "HOTSPARE"; default: - return "UNKNOWN"; + return "Invalid state value"; } } @@ -365,7 +367,7 @@ const char *hr_get_layout_str(hr_level_t level, uint8_t layout) case HR_RLQ_RAID4_N: return "RAID-4 Non-Rotating Parity N"; default: - return "RAID-4 INVALID"; + return "Invalid RAID 4 layout"; } case HR_LVL_5: switch (layout) { @@ -376,10 +378,10 @@ const char *hr_get_layout_str(hr_level_t level, uint8_t layout) case HR_RLQ_RAID5_NC: return "RAID-5 Rotating Parity N with Data Continuation"; default: - return "RAID-5 INVALID"; + return "Invalid RAID 5 layout"; } default: - return "INVALID"; + return "Invalid RAID level"; } } diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 6934fe9e0f..5787a2a13e 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -110,7 +110,7 @@ errno_t hr_raid1_create(hr_volume_t *new_volume) fibril_rwlock_read_lock(&new_volume->states_lock); hr_vol_status_t state = new_volume->status; fibril_rwlock_read_unlock(&new_volume->states_lock); - if (state == HR_VOL_FAULTY || state == HR_VOL_INVALID) + if (state == HR_VOL_FAULTY || state == HR_VOL_NONE) return EINVAL; rc = hr_register_volume(new_volume); @@ -328,7 +328,7 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, hr_vol_status_t vol_state = vol->status; fibril_rwlock_read_unlock(&vol->states_lock); - if (vol_state == HR_VOL_FAULTY || vol_state == HR_VOL_INVALID) + if (vol_state == HR_VOL_FAULTY || vol_state == HR_VOL_NONE) return EIO; if (type == HR_BD_READ || type == HR_BD_WRITE) @@ -661,7 +661,7 @@ static errno_t swap_hs(hr_volume_t *vol, size_t bad, size_t hs) hr_update_ext_status(vol, bad, HR_EXT_HOTSPARE); hr_update_hotspare_svc_id(vol, hs, 0); - hr_update_hotspare_status(vol, hs, HR_EXT_INVALID); + hr_update_hotspare_status(vol, hs, HR_EXT_MISSING); vol->hotspare_no--; From e494d7b8c33117ef5ea8ffd1da396186c1795a8b Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 7 Mar 2025 21:54:30 +0100 Subject: [PATCH 145/324] hr: initialize hotspare states to MISSING --- uspace/srv/bd/hr/util.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index e9e2640660..76a4171141 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -83,6 +83,9 @@ errno_t hr_init_devs(hr_volume_t *vol) } } + for (i = 0; i < HR_MAX_HOTSPARES; i++) + vol->hotspares[i].status = HR_EXT_MISSING; + return rc; } From e3e53cc1db1673f6fc3a0d1083490b9253ec3685 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 14 Mar 2025 21:53:40 +0100 Subject: [PATCH 146/324] hr: var.h: remove struct hr_deferred_invalidation --- uspace/srv/bd/hr/var.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index d5185962aa..6c92e1438c 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -58,12 +58,6 @@ typedef struct hr_ops { errno_t (*add_hotspare)(hr_volume_t *, service_id_t); } hr_ops_t; -typedef struct hr_deferred_invalidation { - link_t link; - size_t index; - service_id_t svc_id; -} hr_deferred_invalidation_t; - typedef struct hr_volume { hr_ops_t hr_ops; bd_srvs_t hr_bds; From de8110485425ef2ffd114ec22795252b57581d4c Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 23 Mar 2025 17:14:36 +0100 Subject: [PATCH 147/324] hr: style headers --- uspace/lib/device/include/hr.h | 56 +++++++------- uspace/srv/bd/hr/var.h | 136 ++++++++++++++++----------------- 2 files changed, 93 insertions(+), 99 deletions(-) diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index 43d730688d..214c6683e1 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Miroslav Cimerman + * Copyright (c) 2025 Miroslav Cimerman * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -89,42 +89,40 @@ typedef struct hr { } hr_t; typedef struct hr_config { - char devname[HR_DEVNAME_LEN]; - service_id_t devs[HR_MAX_EXTENTS]; - size_t dev_no; - hr_level_t level; + char devname[HR_DEVNAME_LEN]; + service_id_t devs[HR_MAX_EXTENTS]; + size_t dev_no; + hr_level_t level; } hr_config_t; typedef struct hr_extent { - service_id_t svc_id; - hr_ext_status_t status; + service_id_t svc_id; + hr_ext_status_t status; } hr_extent_t; typedef struct hr_vol_info { - hr_extent_t extents[HR_MAX_EXTENTS]; - hr_extent_t hotspares[HR_MAX_HOTSPARES]; - size_t extent_no; - size_t hotspare_no; - service_id_t svc_id; - hr_level_t level; - uint64_t nblocks; - uint32_t strip_size; - size_t bsize; - hr_vol_status_t status; - uint8_t layout; + hr_extent_t extents[HR_MAX_EXTENTS]; + hr_extent_t hotspares[HR_MAX_HOTSPARES]; + size_t extent_no; + size_t hotspare_no; + service_id_t svc_id; + hr_level_t level; + uint64_t nblocks; + uint32_t strip_size; + size_t bsize; + hr_vol_status_t status; + uint8_t layout; } hr_vol_info_t; -extern errno_t hr_sess_init(hr_t **); -extern void hr_sess_destroy(hr_t *); - -extern errno_t hr_create(hr_t *, hr_config_t *, bool); -extern errno_t hr_stop(const char *, long); -extern errno_t hr_add_hotspare(service_id_t, service_id_t); -extern errno_t hr_print_status(void); - -extern const char *hr_get_vol_status_msg(hr_vol_status_t); -extern const char *hr_get_ext_status_msg(hr_ext_status_t); -extern const char *hr_get_layout_str(hr_level_t, uint8_t); +extern errno_t hr_sess_init(hr_t **); +extern void hr_sess_destroy(hr_t *); +extern errno_t hr_create(hr_t *, hr_config_t *, bool); +extern errno_t hr_stop(const char *, long); +extern errno_t hr_add_hotspare(service_id_t, service_id_t); +extern errno_t hr_print_status(void); +extern const char *hr_get_vol_status_msg(hr_vol_status_t); +extern const char *hr_get_ext_status_msg(hr_ext_status_t); +extern const char *hr_get_layout_str(hr_level_t, uint8_t); #endif diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index 6c92e1438c..2f2f2cd40e 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -44,65 +44,60 @@ #include "fge.h" -#define NAME "hr" - -#define HR_STRIP_SIZE DATA_XFER_LIMIT +#define NAME "hr" +#define HR_STRIP_SIZE DATA_XFER_LIMIT struct hr_volume; typedef struct hr_volume hr_volume_t; typedef struct hr_ops { - errno_t (*create)(hr_volume_t *); - errno_t (*init)(hr_volume_t *); - void (*status_event)(hr_volume_t *); - errno_t (*add_hotspare)(hr_volume_t *, service_id_t); + errno_t (*create)(hr_volume_t *); + errno_t (*init)(hr_volume_t *); + void (*status_event)(hr_volume_t *); + errno_t (*add_hotspare)(hr_volume_t *, service_id_t); } hr_ops_t; typedef struct hr_volume { - hr_ops_t hr_ops; - bd_srvs_t hr_bds; - - link_t lvolumes; /* protected by static hr_volumes_lock in hr.c */ - - /* - * XXX: will be gone after all paralelization, but still used - * in yet-unparallelized levels + link_t lvolumes; /* link to all volumes list */ + hr_ops_t hr_ops; /* level init and create fcns */ + bd_srvs_t hr_bds; /* block interface to the vol */ + service_id_t svc_id; /* service id */ + + fibril_mutex_t lock; /* XXX: gone after para */ + list_t range_lock_list; /* list of range locks */ + fibril_mutex_t range_lock_list_lock; /* range locks list lock */ + hr_fpool_t *fge; /* fibril pool */ + + /* invariants */ + size_t extent_no; /* number of extents */ + size_t bsize; /* block size */ + uint64_t nblocks; /* no. of all usable blocks */ + uint64_t data_blkno; /* no. of user usable blocks */ + uint64_t data_offset; /* user data offset in blocks */ + uint32_t strip_size; /* strip size */ + hr_level_t level; /* volume level */ + uint8_t layout; /* RAID Level Qualifier */ + char devname[HR_DEVNAME_LEN]; + + hr_extent_t extents[HR_MAX_EXTENTS]; + fibril_rwlock_t extents_lock; /* extent service id lock */ + + size_t hotspare_no; /* no. of available hotspares */ + hr_extent_t hotspares[HR_MAX_HOTSPARES + HR_MAX_EXTENTS]; + fibril_mutex_t hotspare_lock; /* lock protecting hotspares */ + + fibril_rwlock_t states_lock; /* states lock */ + + _Atomic bool state_dirty; /* dirty state */ + + /* XXX: unportable for 32-bit? + * + * Add macros for locking or atomic increment depending + * on the platform? */ - fibril_mutex_t lock; - - list_t range_lock_list; - fibril_mutex_t range_lock_list_lock; - - hr_fpool_t *fge; - - /* after assembly, these are invariant */ - size_t extent_no; - size_t bsize; - uint64_t nblocks; - uint64_t data_blkno; - uint64_t data_offset; /* in blocks */ - uint32_t strip_size; - hr_level_t level; - uint8_t layout; /* RAID Level Qualifier */ - service_id_t svc_id; - char devname[HR_DEVNAME_LEN]; - - size_t hotspare_no; - hr_extent_t hotspares[HR_MAX_HOTSPARES + HR_MAX_EXTENTS]; - - /* protects hotspares (hotspares.{svc_id,status}, hotspare_no) */ - fibril_mutex_t hotspare_lock; - - hr_extent_t extents[HR_MAX_EXTENTS]; - /* protects extents ordering (extents.svc_id) */ - fibril_rwlock_t extents_lock; - /* protects states (extents.status, hr_volume_t.status) */ - fibril_rwlock_t states_lock; - - _Atomic bool state_dirty; - _Atomic uint64_t rebuild_blk; - uint64_t counter; /* metadata syncing */ - hr_vol_status_t status; + _Atomic uint64_t rebuild_blk; /* rebuild position */ + uint64_t counter; /* TODO: metadata syncing */ + hr_vol_status_t status; /* volume status */ } hr_volume_t; typedef enum { @@ -112,32 +107,33 @@ typedef enum { } hr_bd_op_type_t; typedef struct hr_range_lock { - fibril_mutex_t lock; - link_t link; - hr_volume_t *vol; - uint64_t off; - uint64_t len; - size_t pending; /* protected by vol->range_lock_list_lock */ - bool ignore; /* protected by vol->range_lock_list_lock */ + link_t link; + fibril_mutex_t lock; + hr_volume_t *vol; /* back-pointer to volume */ + uint64_t off; /* start of the range */ + uint64_t len; /* length of the range */ + + size_t pending; /* prot. by vol->range_lock_list_lock */ + bool ignore; /* prot. by vol->range_lock_list_lock */ } hr_range_lock_t; -extern errno_t hr_init_devs(hr_volume_t *); -extern void hr_fini_devs(hr_volume_t *); +extern errno_t hr_init_devs(hr_volume_t *); +extern void hr_fini_devs(hr_volume_t *); -extern errno_t hr_raid0_create(hr_volume_t *); -extern errno_t hr_raid1_create(hr_volume_t *); -extern errno_t hr_raid5_create(hr_volume_t *); +extern errno_t hr_raid0_create(hr_volume_t *); +extern errno_t hr_raid1_create(hr_volume_t *); +extern errno_t hr_raid5_create(hr_volume_t *); -extern errno_t hr_raid0_init(hr_volume_t *); -extern errno_t hr_raid1_init(hr_volume_t *); -extern errno_t hr_raid5_init(hr_volume_t *); +extern errno_t hr_raid0_init(hr_volume_t *); +extern errno_t hr_raid1_init(hr_volume_t *); +extern errno_t hr_raid5_init(hr_volume_t *); -extern void hr_raid0_status_event(hr_volume_t *); -extern void hr_raid1_status_event(hr_volume_t *); -extern void hr_raid5_status_event(hr_volume_t *); +extern void hr_raid0_status_event(hr_volume_t *); +extern void hr_raid1_status_event(hr_volume_t *); +extern void hr_raid5_status_event(hr_volume_t *); -extern errno_t hr_raid1_add_hotspare(hr_volume_t *, service_id_t); -extern errno_t hr_raid5_add_hotspare(hr_volume_t *, service_id_t); +extern errno_t hr_raid1_add_hotspare(hr_volume_t *, service_id_t); +extern errno_t hr_raid5_add_hotspare(hr_volume_t *, service_id_t); #endif From 2958e704859548e37defb3c6f939d10b4b2ddc83 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 23 Mar 2025 17:36:48 +0100 Subject: [PATCH 148/324] hr: var.h: revert hotspare no. back from invalidations --- uspace/srv/bd/hr/var.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index 2f2f2cd40e..5ba2152f59 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -83,7 +83,7 @@ typedef struct hr_volume { fibril_rwlock_t extents_lock; /* extent service id lock */ size_t hotspare_no; /* no. of available hotspares */ - hr_extent_t hotspares[HR_MAX_HOTSPARES + HR_MAX_EXTENTS]; + hr_extent_t hotspares[HR_MAX_HOTSPARES]; fibril_mutex_t hotspare_lock; /* lock protecting hotspares */ fibril_rwlock_t states_lock; /* states lock */ From 5fe0b9b5e15941a3aa61414e8b65d2db73575b4b Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 24 Mar 2025 14:22:03 +0100 Subject: [PATCH 149/324] hr: var.h: comment cstyle --- uspace/srv/bd/hr/var.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index 5ba2152f59..afce33b6db 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -90,7 +90,8 @@ typedef struct hr_volume { _Atomic bool state_dirty; /* dirty state */ - /* XXX: unportable for 32-bit? + /* + * XXX: unportable for 32-bit? * * Add macros for locking or atomic increment depending * on the platform? From a57dde49ad2bf8c8b7f23fde7e298e3a83f565db Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 28 Mar 2025 22:28:21 +0100 Subject: [PATCH 150/324] hr: use __func__ for DEBUG printing fcn names --- uspace/srv/bd/hr/hr.c | 14 +++++++------- uspace/srv/bd/hr/raid0.c | 4 ++-- uspace/srv/bd/hr/raid1.c | 4 ++-- uspace/srv/bd/hr/superblock.c | 10 +++++----- uspace/srv/bd/hr/util.c | 8 ++++---- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 25c6b75864..f7c560fa0f 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -100,7 +100,7 @@ static errno_t hr_remove_volume(service_id_t svc_id) static void hr_create_srv(ipc_call_t *icall, bool assemble) { - HR_DEBUG("hr_create_srv()\n"); + HR_DEBUG("%s()", __func__); errno_t rc; size_t i, size; @@ -231,7 +231,7 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) new_volume->hr_ops.add_hotspare = hr_raid5_add_hotspare; break; default: - HR_ERROR("unkown level: %d, aborting\n", new_volume->level); + HR_DEBUG("unkown level: %d, aborting\n", new_volume->level); rc = EINVAL; goto error; } @@ -288,7 +288,7 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) static void hr_stop_srv(ipc_call_t *icall) { - HR_DEBUG("hr_stop_srv()\n"); + HR_DEBUG("%s()", __func__); errno_t rc = EOK; service_id_t svc_id; @@ -329,7 +329,7 @@ static void hr_stop_srv(ipc_call_t *icall) static void hr_add_hotspare_srv(ipc_call_t *icall) { - HR_DEBUG("hr_add_hotspare()\n"); + HR_DEBUG("%s()", __func__); errno_t rc = EOK; service_id_t vol_svc_id; @@ -359,7 +359,7 @@ static void hr_add_hotspare_srv(ipc_call_t *icall) static void hr_print_status_srv(ipc_call_t *icall) { - HR_DEBUG("hr_status_srv()\n"); + HR_DEBUG("%s()", __func__); errno_t rc; size_t vol_cnt = 0; @@ -427,7 +427,7 @@ static void hr_print_status_srv(ipc_call_t *icall) static void hr_ctl_conn(ipc_call_t *icall, void *arg) { - HR_DEBUG("hr_ctl_conn()\n"); + HR_DEBUG("%s()", __func__); async_accept_0(icall); @@ -465,7 +465,7 @@ static void hr_ctl_conn(ipc_call_t *icall, void *arg) static void hr_client_conn(ipc_call_t *icall, void *arg) { - HR_DEBUG("hr_client_conn()\n"); + HR_DEBUG("%s()", __func__); hr_volume_t *vol; diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index 07fd6fc267..8f3b9c6fa9 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -131,13 +131,13 @@ void hr_raid0_status_event(hr_volume_t *vol) static errno_t hr_raid0_bd_open(bd_srvs_t *bds, bd_srv_t *bd) { - HR_DEBUG("hr_bd_open()\n"); + HR_DEBUG("%s()", __func__); return EOK; } static errno_t hr_raid0_bd_close(bd_srv_t *bd) { - HR_DEBUG("hr_bd_close()\n"); + HR_DEBUG("%s()", __func__); return EOK; } diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 5787a2a13e..14bdb8a053 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -146,7 +146,7 @@ void hr_raid1_status_event(hr_volume_t *vol) errno_t hr_raid1_add_hotspare(hr_volume_t *vol, service_id_t hotspare) { - HR_DEBUG("hr_raid1_add_hotspare()\n"); + HR_DEBUG("%s()", __func__); errno_t rc = EOK; @@ -469,7 +469,7 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, */ static errno_t hr_raid1_rebuild(void *arg) { - HR_DEBUG("hr_raid1_rebuild()\n"); + HR_DEBUG("%s()", __func__); hr_volume_t *vol = arg; void *buf = NULL; diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index e5a93b6c65..d5948c9944 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Miroslav Cimerman + * Copyright (c) 2025 Miroslav Cimerman * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -55,7 +55,7 @@ static errno_t validate_meta(hr_metadata_t *); errno_t hr_write_meta_to_vol(hr_volume_t *vol) { - HR_DEBUG("hr_write_meta_to_vol()\n"); + HR_DEBUG("%s()", __func__); errno_t rc; size_t i; @@ -93,7 +93,7 @@ errno_t hr_write_meta_to_vol(hr_volume_t *vol) errno_t hr_write_meta_to_ext(hr_volume_t *vol, size_t ext) { - HR_DEBUG("hr_write_meta_to_vol()\n"); + HR_DEBUG("%s()", __func__); errno_t rc; hr_metadata_t *metadata; @@ -132,7 +132,7 @@ errno_t hr_write_meta_to_ext(hr_volume_t *vol, size_t ext) */ static errno_t hr_fill_meta_from_vol(hr_volume_t *vol, hr_metadata_t *metadata) { - HR_DEBUG("hr_fill_meta_from_vol()\n"); + HR_DEBUG("%s()", __func__); size_t meta_blkno = HR_META_OFF + HR_META_SIZE; @@ -179,7 +179,7 @@ static errno_t validate_meta(hr_metadata_t *md) errno_t hr_fill_vol_from_meta(hr_volume_t *vol) { - HR_DEBUG("hr_get_vol_from_meta()\n"); + HR_DEBUG("%s()", __func__); errno_t rc; hr_metadata_t *metadata; diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 76a4171141..280d45352d 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -58,7 +58,7 @@ extern loc_srv_t *hr_srv; errno_t hr_init_devs(hr_volume_t *vol) { - HR_DEBUG("hr_init_devs()\n"); + HR_DEBUG("%s()", __func__); errno_t rc; size_t i; @@ -91,7 +91,7 @@ errno_t hr_init_devs(hr_volume_t *vol) void hr_fini_devs(hr_volume_t *vol) { - HR_DEBUG("hr_fini_devs()\n"); + HR_DEBUG("%s()", __func__); size_t i; @@ -106,7 +106,7 @@ void hr_fini_devs(hr_volume_t *vol) errno_t hr_register_volume(hr_volume_t *vol) { - HR_DEBUG("hr_register_volume()\n"); + HR_DEBUG("%s()", __func__); errno_t rc; service_id_t new_id; @@ -146,7 +146,7 @@ errno_t hr_register_volume(hr_volume_t *vol) errno_t hr_check_devs(hr_volume_t *vol, uint64_t *rblkno, size_t *rbsize) { - HR_DEBUG("hr_check_devs()\n"); + HR_DEBUG("%s()", __func__); errno_t rc; size_t i, bsize; From b04f7af3fa87551c0aba81bdec7efd8958f1bc62 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 28 Mar 2025 22:29:10 +0100 Subject: [PATCH 151/324] hr: hr.c: add headers --- uspace/srv/bd/hr/hr.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index f7c560fa0f..d918d453b4 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -33,6 +33,7 @@ * @file */ +#include #include #include #include @@ -48,6 +49,7 @@ #include #include #include +#include #include "fge.h" #include "io.h" From 7bfe4688ac150da4717fff57fd8f37bcc99eaafc Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 28 Mar 2025 22:30:03 +0100 Subject: [PATCH 152/324] hr: hr.c: hr_client_conn() return ENOENT --- uspace/srv/bd/hr/hr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index d918d453b4..63a2a7d007 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -479,7 +479,7 @@ static void hr_client_conn(ipc_call_t *icall, void *arg) HR_DEBUG("bd_conn()\n"); vol = hr_get_volume(svc_id); if (vol == NULL) - async_answer_0(icall, EINVAL); + async_answer_0(icall, ENOENT); bd_conn(icall, &vol->hr_bds); } } From 8b51009d8adb87b39341aef74db3eeb0f2a2fa7a Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sat, 29 Mar 2025 00:25:57 +0100 Subject: [PATCH 153/324] hr: auto assembly, refactor Added automatic assembly (with hrctl -A). All disks or their partitions are scanned for HelenRAID metadata and assembly is attempted. Main volume list is now locked with RW lock. The volume list manipulation functions are moved into util.c. hr_{create,destroy}_vol_struct() are implemented for better reusability and modularity. Volume destroy/stop (hrctl -D) now returns EBUSY if someone has still the volume open()-ed. --- uspace/app/hrctl/hrctl.c | 39 +- uspace/lib/device/include/hr.h | 1 + uspace/lib/device/include/ipc/hr.h | 3 +- uspace/lib/device/src/hr.c | 38 +- uspace/srv/bd/hr/hr.c | 155 +++----- uspace/srv/bd/hr/superblock.c | 142 ++++++-- uspace/srv/bd/hr/superblock.h | 61 ++-- uspace/srv/bd/hr/util.c | 549 +++++++++++++++++++++++++++++ uspace/srv/bd/hr/util.h | 42 ++- uspace/srv/bd/hr/var.h | 16 +- 10 files changed, 846 insertions(+), 200 deletions(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index 3316f4c96d..1d2aab2c5c 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Miroslav Cimerman + * Copyright (c) 2025 Miroslav Cimerman * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -44,24 +44,24 @@ #define HRCTL_SAMPLE_CONFIG_PATH "/cfg/sample_hr_config.sif" -static void usage(void); -static errno_t fill_config_devs(int, char **, int, hr_config_t *); -static errno_t load_config(const char *, hr_config_t *); +static void usage(void); +static errno_t fill_config_devs(int, char **, int, hr_config_t *); +static errno_t load_config(const char *, hr_config_t *); static const char usage_str[] = "Usage: hrctl [OPTION]... -n ...\n" "\n" "Options:\n" - " -h, --help display this help and exit\n" + " -h, --help display this message and exit\n" " -C, --create-file=PATH create an array from file,\n" " sample file at: " HRCTL_SAMPLE_CONFIG_PATH "\n" - " -A, --assemble-file=PATH create an array from file\n" + " -A, --auto-assemble try to auto assemble all valid arrays\n" " -s, --status display status of active arrays\n" " -H, --hotspare=DEV add hotspare extent\n" " -D, --destroy destroy/disassemble an active array\n" " -F, --fail-extent fail an extent, use with -D and set it before\n" " -c, --create=NAME create new array\n" - " -a, --assemble=NAME assemble an existing array\n" + " -a, --assemble=NAME assemble from specified extents\n" " -n non-zero number of devices\n" " -l, --level=LEVEL set the RAID level,\n" " valid values: 0, 1, 4, 5\n" @@ -94,7 +94,7 @@ static struct option const long_options[] = { { "create", required_argument, 0, 'c' }, { "level", required_argument, 0, 'l' }, { "create-file", required_argument, 0, 'C' }, - { "assemble-file", required_argument, 0, 'A' }, + { "auto-assemble", no_argument, 0, 'A' }, { "destroy", required_argument, 0, 'D' }, { "fail-extent", required_argument, 0, 'F' }, { "hotspare", required_argument, 0, 'H' }, @@ -252,7 +252,7 @@ int main(int argc, char **argv) optind = 0; while (c != -1) { - c = getopt_long(argc, argv, "hsC:c:A:a:l:0145Ln:D:F:H:", + c = getopt_long(argc, argv, "hsC:c:Aa:l:0145Ln:D:F:H:", long_options, NULL); switch (c) { case 's': @@ -281,14 +281,17 @@ int main(int argc, char **argv) create = true; break; case 'A': - rc = load_config(optarg, cfg); + size_t cnt; + rc = hr_auto_assemble(&cnt); if (rc != EOK) { - printf("hrctl: failed to load config\n"); - free(cfg); - return 1; + /* XXX: here have own error codes */ + printf("hrctl: auto assemble rc: %s\n", + str_error(rc)); + } else { + printf("hrctl: auto assembled %lu volumes\n", + cnt); } - assemble = true; - goto skip; + return rc; case 'a': if (str_size(optarg) > sizeof(cfg->devname) - 1) { printf("hrctl: device name too long\n"); @@ -302,10 +305,8 @@ int main(int argc, char **argv) rc = hr_stop(optarg, fail_extent); free(cfg); if (rc != EOK) { - if (rc == ENOENT) - printf("hrctl: service named \"%s\" does not exist\n", - optarg); - return 1; + printf("hrctl: got %s\n", str_error(rc)); + return rc; } return 0; case 'F': diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index 214c6683e1..9be5b0b5b3 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -117,6 +117,7 @@ typedef struct hr_vol_info { extern errno_t hr_sess_init(hr_t **); extern void hr_sess_destroy(hr_t *); extern errno_t hr_create(hr_t *, hr_config_t *, bool); +extern errno_t hr_auto_assemble(size_t *); extern errno_t hr_stop(const char *, long); extern errno_t hr_add_hotspare(service_id_t, service_id_t); extern errno_t hr_print_status(void); diff --git a/uspace/lib/device/include/ipc/hr.h b/uspace/lib/device/include/ipc/hr.h index 2fb60fb6d3..de5d686c30 100644 --- a/uspace/lib/device/include/ipc/hr.h +++ b/uspace/lib/device/include/ipc/hr.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Miroslav Cimerman + * Copyright (c) 2025 Miroslav Cimerman * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -40,6 +40,7 @@ typedef enum { HR_CREATE = IPC_FIRST_USER_METHOD, HR_ASSEMBLE, + HR_AUTO_ASSEMBLE, HR_STOP, HR_ADD_HOTSPARE, HR_STATUS diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index 7f44120ace..7bbbdc7dde 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -114,6 +114,41 @@ errno_t hr_create(hr_t *hr, hr_config_t *hr_config, bool assemble) return EOK; } +errno_t hr_auto_assemble(size_t *rassembled_cnt) +{ + hr_t *hr; + errno_t rc; + size_t assembled_cnt; + + rc = hr_sess_init(&hr); + if (rc != EOK) + return rc; + + async_exch_t *exch = async_exchange_begin(hr->sess); + if (exch == NULL) { + rc = EINVAL; + goto error; + } + + aid_t req = async_send_0(exch, HR_AUTO_ASSEMBLE, NULL); + + rc = async_data_read_start(exch, &assembled_cnt, sizeof(size_t)); + if (rc != EOK) { + async_exchange_end(exch); + async_forget(req); + return rc; + } + + async_exchange_end(exch); + async_wait_for(req, &rc); + + if (rassembled_cnt != NULL) + *rassembled_cnt = assembled_cnt; +error: + hr_sess_destroy(hr); + return rc; +} + static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info) { errno_t rc; @@ -217,9 +252,6 @@ errno_t hr_stop(const char *devname, long extent) } rc = async_req_2_0(exch, HR_STOP, svc_id, extent); async_exchange_end(exch); - - if (rc != EOK) - goto error; error: hr_sess_destroy(hr); return rc; diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 63a2a7d007..24ab11c58b 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -58,46 +58,45 @@ #include "var.h" loc_srv_t *hr_srv; - -static fibril_mutex_t hr_volumes_lock; -static list_t hr_volumes; +list_t hr_volumes; +fibril_rwlock_t hr_volumes_lock; static service_id_t ctl_sid; -static hr_volume_t *hr_get_volume(service_id_t svc_id) +static void hr_auto_assemble_srv(ipc_call_t *icall) { - HR_DEBUG("hr_get_volume(): (%" PRIun ")\n", svc_id); + HR_DEBUG("%s()", __func__); - fibril_mutex_lock(&hr_volumes_lock); - list_foreach(hr_volumes, lvolumes, hr_volume_t, vol) { - if (vol->svc_id == svc_id) { - fibril_mutex_unlock(&hr_volumes_lock); - return vol; - } + errno_t rc; + size_t size; + size_t assembled_cnt = 0; + ipc_call_t call; + + if (!async_data_read_receive(&call, &size)) { + async_answer_0(icall, EREFUSED); + return; } - fibril_mutex_unlock(&hr_volumes_lock); - return NULL; -} + if (size != sizeof(size_t)) { + async_answer_0(icall, EINVAL); + return; + } -static errno_t hr_remove_volume(service_id_t svc_id) -{ - HR_DEBUG("hr_remove_volume(): (%" PRIun ")\n", svc_id); + rc = hr_util_try_auto_assemble(&assembled_cnt); + if (rc != EOK) { + async_answer_0(&call, rc); + async_answer_0(icall, rc); + return; + } - fibril_mutex_lock(&hr_volumes_lock); - list_foreach(hr_volumes, lvolumes, hr_volume_t, vol) { - if (vol->svc_id == svc_id) { - hr_fpool_destroy(vol->fge); - hr_fini_devs(vol); - list_remove(&vol->lvolumes); - free(vol); - fibril_mutex_unlock(&hr_volumes_lock); - return EOK; - } + rc = async_data_read_finalize(&call, &assembled_cnt, size); + if (rc != EOK) { + async_answer_0(&call, rc); + async_answer_0(icall, rc); + return; } - fibril_mutex_unlock(&hr_volumes_lock); - return ENOENT; + async_answer_0(icall, EOK); } static void hr_create_srv(ipc_call_t *icall, bool assemble) @@ -153,21 +152,12 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) } } - new_volume = calloc(1, sizeof(hr_volume_t)); - if (new_volume == NULL) { - free(cfg); - async_answer_0(icall, ENOMEM); - return; - } - - hr_fpool_t *fge = hr_fpool_create(16, 32, sizeof(hr_io_t)); - if (fge == NULL) { - free(new_volume); + rc = hr_create_vol_struct(&new_volume, cfg->level); + if (rc != EOK) { free(cfg); - async_answer_0(icall, ENOMEM); + async_answer_0(icall, rc); return; } - new_volume->fge = fge; str_cpy(new_volume->devname, HR_DEVNAME_LEN, cfg->devname); for (i = 0; i < cfg->dev_no; i++) @@ -175,12 +165,6 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) new_volume->level = cfg->level; new_volume->extent_no = cfg->dev_no; - if (assemble) { - if (cfg->level != HR_LVL_UNKNOWN) - HR_WARN("level manually set when assembling, ingoring"); - new_volume->level = HR_LVL_UNKNOWN; - } - rc = hr_init_devs(new_volume); if (rc != EOK) { free(cfg); @@ -189,6 +173,12 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) return; } + if (assemble) { + if (cfg->level != HR_LVL_UNKNOWN) + HR_DEBUG("level manually set when assembling, ingoring"); + new_volume->level = HR_LVL_UNKNOWN; + } + if (assemble) { /* just bsize needed for reading metadata later */ rc = hr_check_devs(new_volume, NULL, &new_volume->bsize); @@ -200,44 +190,6 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) goto error; } - switch (new_volume->level) { - case HR_LVL_1: - if (!assemble) - new_volume->layout = 0x00; /* XXX: yet unused */ - new_volume->hr_ops.create = hr_raid1_create; - new_volume->hr_ops.init = hr_raid1_init; - new_volume->hr_ops.status_event = hr_raid1_status_event; - new_volume->hr_ops.add_hotspare = hr_raid1_add_hotspare; - break; - case HR_LVL_0: - if (!assemble) - new_volume->layout = 0x00; - new_volume->hr_ops.create = hr_raid0_create; - new_volume->hr_ops.init = hr_raid0_init; - new_volume->hr_ops.status_event = hr_raid0_status_event; - break; - case HR_LVL_4: - if (!assemble) - new_volume->layout = HR_RLQ_RAID4_N; - new_volume->hr_ops.create = hr_raid5_create; - new_volume->hr_ops.init = hr_raid5_init; - new_volume->hr_ops.status_event = hr_raid5_status_event; - new_volume->hr_ops.add_hotspare = hr_raid5_add_hotspare; - break; - case HR_LVL_5: - if (!assemble) - new_volume->layout = HR_RLQ_RAID5_NR; - new_volume->hr_ops.create = hr_raid5_create; - new_volume->hr_ops.init = hr_raid5_init; - new_volume->hr_ops.status_event = hr_raid5_status_event; - new_volume->hr_ops.add_hotspare = hr_raid5_add_hotspare; - break; - default: - HR_DEBUG("unkown level: %d, aborting\n", new_volume->level); - rc = EINVAL; - goto error; - } - if (!assemble) { new_volume->hr_ops.init(new_volume); if (rc != EOK) @@ -248,26 +200,13 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) goto error; } - fibril_mutex_initialize(&new_volume->lock); /* XXX: will remove this */ - - fibril_rwlock_initialize(&new_volume->extents_lock); - fibril_rwlock_initialize(&new_volume->states_lock); - - fibril_mutex_initialize(&new_volume->hotspare_lock); - - list_initialize(&new_volume->range_lock_list); - fibril_mutex_initialize(&new_volume->range_lock_list_lock); - - atomic_init(&new_volume->rebuild_blk, 0); - atomic_init(&new_volume->state_dirty, false); - rc = new_volume->hr_ops.create(new_volume); if (rc != EOK) goto error; - fibril_mutex_lock(&hr_volumes_lock); + fibril_rwlock_write_lock(&hr_volumes_lock); list_append(&new_volume->lvolumes, &hr_volumes); - fibril_mutex_unlock(&hr_volumes_lock); + fibril_rwlock_write_unlock(&hr_volumes_lock); if (assemble) { HR_DEBUG("assembled volume \"%s\" (%" PRIun ")\n", @@ -282,9 +221,7 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) return; error: free(cfg); - free(fge); - hr_fini_devs(new_volume); - free(new_volume); + hr_destroy_vol_struct(new_volume); async_answer_0(icall, rc); } @@ -312,7 +249,6 @@ static void hr_stop_srv(ipc_call_t *icall) async_answer_0(icall, rc); return; } - rc = loc_service_unregister(hr_srv, svc_id); } else { fibril_rwlock_write_lock(&vol->states_lock); fibril_rwlock_read_lock(&vol->extents_lock); @@ -369,7 +305,7 @@ static void hr_print_status_srv(ipc_call_t *icall) ipc_call_t call; size_t size; - fibril_mutex_lock(&hr_volumes_lock); + fibril_rwlock_read_lock(&hr_volumes_lock); vol_cnt = list_count(&hr_volumes); @@ -418,11 +354,11 @@ static void hr_print_status_srv(ipc_call_t *icall) goto error; } - fibril_mutex_unlock(&hr_volumes_lock); + fibril_rwlock_read_unlock(&hr_volumes_lock); async_answer_0(icall, EOK); return; error: - fibril_mutex_unlock(&hr_volumes_lock); + fibril_rwlock_read_unlock(&hr_volumes_lock); async_answer_0(&call, rc); async_answer_0(icall, rc); } @@ -450,6 +386,9 @@ static void hr_ctl_conn(ipc_call_t *icall, void *arg) case HR_ASSEMBLE: hr_create_srv(&call, true); break; + case HR_AUTO_ASSEMBLE: + hr_auto_assemble_srv(&call); + break; case HR_STOP: hr_stop_srv(&call); break; @@ -496,7 +435,7 @@ int main(int argc, char **argv) return 1; } - fibril_mutex_initialize(&hr_volumes_lock); + fibril_rwlock_initialize(&hr_volumes_lock); list_initialize(&hr_volumes); async_set_fallback_port_handler(hr_client_conn, NULL); diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index d5948c9944..cbe5b68a45 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -51,7 +51,6 @@ static errno_t read_metadata(service_id_t, hr_metadata_t *); static errno_t hr_fill_meta_from_vol(hr_volume_t *, hr_metadata_t *); -static errno_t validate_meta(hr_metadata_t *); errno_t hr_write_meta_to_vol(hr_volume_t *vol) { @@ -70,21 +69,24 @@ errno_t hr_write_meta_to_vol(hr_volume_t *vol) if (rc != EOK) goto error; + /* rndgen */ + fibril_usleep(1000); + rc = uuid_generate(&uuid); + if (rc != EOK) + goto error; + + /* XXX: for now we just copy byte by byte as "encoding" */ + memcpy(metadata->uuid, &uuid, sizeof(HR_UUID_LEN)); + /* uuid_encode(&uuid, metadata->uuid); */ + for (i = 0; i < vol->extent_no; i++) { metadata->index = host2uint32_t_le(i); - rc = uuid_generate(&uuid); - if (rc != EOK) - goto error; - uuid_encode(&uuid, metadata->uuid); - rc = block_write_direct(vol->extents[i].svc_id, HR_META_OFF, HR_META_SIZE, metadata); if (rc != EOK) goto error; - /* rndgen */ - fibril_usleep(1000); } error: free(metadata); @@ -99,6 +101,7 @@ errno_t hr_write_meta_to_ext(hr_volume_t *vol, size_t ext) hr_metadata_t *metadata; uuid_t uuid; + /* XXX: use scratchpad */ metadata = calloc(1, HR_META_SIZE * vol->bsize); if (metadata == NULL) return ENOMEM; @@ -151,30 +154,31 @@ static errno_t hr_fill_meta_from_vol(hr_volume_t *vol, hr_metadata_t *metadata) return EINVAL; } - metadata->magic = host2uint64_t_le(HR_MAGIC); - metadata->version = host2uint32_t_le(~(0U)); /* unused */ + /* XXX: use scratchpad */ + str_cpy(metadata->magic, HR_MAGIC_SIZE, HR_MAGIC_STR); + metadata->nblocks = host2uint64_t_le(vol->nblocks); + metadata->data_blkno = host2uint64_t_le(vol->data_blkno); + metadata->truncated_blkno = host2uint64_t_le(vol->truncated_blkno); + metadata->data_offset = host2uint64_t_le(vol->data_offset); + metadata->counter = host2uint64_t_le(~(0UL)); /* XXX: unused */ + metadata->version = host2uint32_t_le(~(0U)); /* XXX: unused */ metadata->extent_no = host2uint32_t_le(vol->extent_no); /* index filled separately for each extent */ metadata->level = host2uint32_t_le(vol->level); metadata->layout = host2uint32_t_le(vol->layout); metadata->strip_size = host2uint32_t_le(vol->strip_size); - metadata->nblocks = host2uint64_t_le(vol->nblocks); - metadata->data_blkno = host2uint64_t_le(vol->data_blkno); - metadata->data_offset = host2uint64_t_le(vol->data_offset); - metadata->counter = host2uint64_t_le(~(0UL)); /* unused */ - /* UUID generated separately for each extent */ + metadata->bsize = host2uint32_t_le(vol->bsize); str_cpy(metadata->devname, HR_DEVNAME_LEN, vol->devname); return EOK; } -static errno_t validate_meta(hr_metadata_t *md) +bool hr_valid_md_magic(hr_metadata_t *md) { - if (uint64_t_le2host(md->magic) != HR_MAGIC) { - HR_ERROR("invalid magic\n"); - return EINVAL; - } - return EOK; + if (str_lcmp(md->magic, HR_MAGIC_STR, HR_MAGIC_SIZE) != 0) + return false; + + return true; } errno_t hr_fill_vol_from_meta(hr_volume_t *vol) @@ -202,8 +206,7 @@ errno_t hr_fill_vol_from_meta(hr_volume_t *vol) rc = read_metadata(assembly_svc_id_order[i], metadata); if (rc != EOK) goto end; - rc = validate_meta(metadata); - if (rc != EOK) + if (!hr_valid_md_magic(metadata)) goto end; md_order_indices[i] = uint32_t_le2host(metadata->index); } @@ -243,6 +246,7 @@ errno_t hr_fill_vol_from_meta(hr_volume_t *vol) vol->nblocks = uint64_t_le2host(metadata->nblocks); vol->data_blkno = uint64_t_le2host(metadata->data_blkno); vol->data_offset = uint64_t_le2host(metadata->data_offset); + vol->bsize = uint32_t_le2host(metadata->bsize); vol->counter = uint64_t_le2host(0x00); /* unused */ if (str_cmp(metadata->devname, vol->devname) != 0) { @@ -273,5 +277,97 @@ static errno_t read_metadata(service_id_t dev, hr_metadata_t *metadata) return EOK; } +errno_t hr_get_metadata_block(service_id_t dev, void **rblock) +{ + HR_DEBUG("%s()", __func__); + errno_t rc; + uint64_t blkno; + size_t bsize; + void *block; + + rc = block_get_bsize(dev, &bsize); + if (rc != EOK) + return rc; + + if (bsize < sizeof(hr_metadata_t)) + return EINVAL; + + rc = block_get_nblocks(dev, &blkno); + if (rc != EOK) + return rc; + + if (blkno < HR_META_OFF + HR_META_SIZE) + return EINVAL; + + block = malloc(bsize); + if (block == NULL) + return ENOMEM; + + rc = block_read_direct(dev, HR_META_OFF, HR_META_SIZE, block); + if (rc != EOK) { + free(block); + return rc; + } + + if (rblock == NULL) { + free(block); + return EINVAL; + } + + *rblock = block; + return EOK; +} + +void hr_decode_metadata_from_block(void *block, hr_metadata_t *metadata) +{ + /* + * Use scratch metadata for easier decoding without the need + * for manualy specifying offsets. + */ + hr_metadata_t scratch_md; + memcpy(&scratch_md, block, sizeof(hr_metadata_t)); + + memcpy(metadata->magic, scratch_md.magic, HR_MAGIC_SIZE); + memcpy(metadata->uuid, scratch_md.uuid, HR_UUID_LEN); + metadata->nblocks = uint64_t_le2host(scratch_md.nblocks); + metadata->data_blkno = uint64_t_le2host(scratch_md.data_blkno); + metadata->truncated_blkno = uint64_t_le2host( + scratch_md.truncated_blkno); + metadata->data_offset = uint64_t_le2host(scratch_md.data_offset); + metadata->counter = uint64_t_le2host(scratch_md.counter); + metadata->version = uint32_t_le2host(scratch_md.version); + metadata->extent_no = uint32_t_le2host(scratch_md.extent_no); + metadata->index = uint32_t_le2host(scratch_md.index); + metadata->level = uint32_t_le2host(scratch_md.level); + metadata->layout = uint32_t_le2host(scratch_md.layout); + metadata->strip_size = uint32_t_le2host(scratch_md.strip_size); + metadata->bsize = uint64_t_le2host(scratch_md.bsize); + memcpy(metadata->devname, scratch_md.devname, HR_DEVNAME_LEN); +} + +void hr_metadata_dump(hr_metadata_t *metadata) +{ + printf("\tmagic: %s\n", metadata->magic); + printf("\tUUID: "); + for (size_t i = 0; i < HR_UUID_LEN; ++i) { + printf("%.2X", metadata->uuid[i]); + if (i + 1 < HR_UUID_LEN) + printf(" "); + } + printf("\n"); + printf("\tnblocks: %lu\n", metadata->nblocks); + printf("\tdata_blkno: %lu\n", metadata->data_blkno); + printf("\ttruncated_blkno: %lu\n", metadata->truncated_blkno); + printf("\tdata_offset: %lu\n", metadata->data_offset); + printf("\tcounter: %lu\n", metadata->counter); + printf("\tversion: %u\n", metadata->version); + printf("\textent_no: %u\n", metadata->extent_no); + printf("\tindex: %u\n", metadata->index); + printf("\tlevel: %u\n", metadata->level); + printf("\tlayout: %u\n", metadata->layout); + printf("\tstrip_size: %u\n", metadata->strip_size); + printf("\tdevname: %s\n", metadata->devname); +} + /** @} */ diff --git a/uspace/srv/bd/hr/superblock.h b/uspace/srv/bd/hr/superblock.h index 7bce621dca..7f6c1f3f4e 100644 --- a/uspace/srv/bd/hr/superblock.h +++ b/uspace/srv/bd/hr/superblock.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Miroslav Cimerman + * Copyright (c) 2025 Miroslav Cimerman * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -38,38 +38,51 @@ #include "var.h" -#define HR_META_SIZE 1 /* in blocks */ -#define HR_META_OFF 7 /* in blocks */ -#define HR_DATA_OFF (HR_META_SIZE + HR_META_OFF) +#define HR_META_SIZE 1 /* in blocks */ +#define HR_META_OFF 7 /* in blocks */ +#define HR_DATA_OFF (HR_META_OFF + HR_META_SIZE) -#define HR_MAGIC 0x4420492041205248LLU -#define HR_UUID_LEN 16 +#define HR_MAGIC_STR "HelenRAID" +#define HR_MAGIC_SIZE 16 +#define HR_UUID_LEN 16 +/* #define HR_METADATA_VERSION 0 */ -typedef struct hr_metadata { - uint64_t magic; - uint32_t version; /* unused XXX */ - uint32_t extent_no; +typedef struct hr_metadata hr_metadata_t; +typedef struct hr_volume hr_volume_t; - uint32_t index; /* index of disk in array */ - uint32_t level; - uint32_t layout; - uint32_t strip_size; +struct hr_metadata { + char magic[HR_MAGIC_SIZE]; - uint64_t nblocks; /* all blocks */ - uint64_t data_blkno; /* usable blocks */ + uint8_t uuid[HR_UUID_LEN]; - uint64_t data_offset; /* block where data starts */ + /* TODO: change to blkno */ + uint64_t nblocks; /* all blocks */ + uint64_t data_blkno; /* usable blocks */ - uint64_t counter; /* unused */ + uint64_t truncated_blkno; /* usable blocks */ + uint64_t data_offset; - uint8_t uuid[HR_UUID_LEN]; + uint64_t counter; /* yet unused */ + uint32_t version; /* yet unused */ + uint32_t extent_no; - char devname[HR_DEVNAME_LEN]; -} hr_metadata_t; + uint32_t index; /* index of extent in volume */ + uint32_t level; + uint32_t layout; + uint32_t strip_size; -extern errno_t hr_write_meta_to_vol(hr_volume_t *); -extern errno_t hr_write_meta_to_ext(hr_volume_t *, size_t); -extern errno_t hr_fill_vol_from_meta(hr_volume_t *); + uint32_t bsize; + + char devname[HR_DEVNAME_LEN]; +}; + +extern errno_t hr_write_meta_to_vol(hr_volume_t *); +extern errno_t hr_write_meta_to_ext(hr_volume_t *, size_t); +extern errno_t hr_fill_vol_from_meta(hr_volume_t *); +extern errno_t hr_get_metadata_block(service_id_t, void **); +extern void hr_decode_metadata_from_block(void *, hr_metadata_t *); +extern void hr_metadata_dump(hr_metadata_t *); +extern bool hr_valid_md_magic(hr_metadata_t *); #endif diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 280d45352d..d2af955369 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -40,11 +40,15 @@ #include #include #include +#include #include #include #include #include +#include +#include "io.h" +#include "superblock.h" #include "util.h" #include "var.h" @@ -55,6 +59,149 @@ static bool hr_range_lock_overlap(hr_range_lock_t *, hr_range_lock_t *); extern loc_srv_t *hr_srv; +extern list_t hr_volumes; +extern fibril_rwlock_t hr_volumes_lock; + +errno_t hr_create_vol_struct(hr_volume_t **rvol, hr_level_t level) +{ + errno_t rc; + + hr_volume_t *vol = calloc(1, sizeof(hr_volume_t)); + if (vol == NULL) + return ENOMEM; + + vol->level = level; + + switch (level) { + case HR_LVL_1: + vol->hr_ops.create = hr_raid1_create; + vol->hr_ops.init = hr_raid1_init; + vol->hr_ops.status_event = hr_raid1_status_event; + vol->hr_ops.add_hotspare = hr_raid1_add_hotspare; + break; + case HR_LVL_0: + vol->hr_ops.create = hr_raid0_create; + vol->hr_ops.init = hr_raid0_init; + vol->hr_ops.status_event = hr_raid0_status_event; + break; + case HR_LVL_4: + vol->hr_ops.create = hr_raid5_create; + vol->hr_ops.init = hr_raid5_init; + vol->hr_ops.status_event = hr_raid5_status_event; + vol->hr_ops.add_hotspare = hr_raid5_add_hotspare; + break; + case HR_LVL_5: + vol->hr_ops.create = hr_raid5_create; + vol->hr_ops.init = hr_raid5_init; + vol->hr_ops.status_event = hr_raid5_status_event; + vol->hr_ops.add_hotspare = hr_raid5_add_hotspare; + break; + default: + HR_DEBUG("unkown level: %d, aborting\n", vol->level); + rc = EINVAL; + goto error; + } + + vol->fge = hr_fpool_create(16, 32, sizeof(hr_io_t)); + if (vol->fge == NULL) { + rc = ENOMEM; + goto error; + } + + vol->status = HR_VOL_NONE; + + for (size_t i = 0; i < HR_MAX_EXTENTS; ++i) + vol->extents[i].status = HR_EXT_MISSING; + + for (size_t i = 0; i < HR_MAX_HOTSPARES; ++i) + vol->extents[i].status = HR_EXT_MISSING; + + fibril_mutex_initialize(&vol->lock); /* XXX: will remove this */ + + fibril_rwlock_initialize(&vol->extents_lock); + fibril_rwlock_initialize(&vol->states_lock); + + fibril_mutex_initialize(&vol->hotspare_lock); + + list_initialize(&vol->range_lock_list); + fibril_mutex_initialize(&vol->range_lock_list_lock); + + atomic_init(&vol->rebuild_blk, 0); + atomic_init(&vol->state_dirty, false); + atomic_init(&vol->open_cnt, 0); + + *rvol = vol; + + return EOK; +error: + free(vol); + return rc; +} + +void hr_destroy_vol_struct(hr_volume_t *vol) +{ + if (vol == NULL) + return; + + hr_fpool_destroy(vol->fge); + hr_fini_devs(vol); + free(vol->in_mem_md); + free(vol); +} + +hr_volume_t *hr_get_volume(service_id_t svc_id) +{ + HR_DEBUG("hr_get_volume(): (%" PRIun ")\n", svc_id); + + hr_volume_t *rvol = NULL; + + fibril_rwlock_read_lock(&hr_volumes_lock); + list_foreach(hr_volumes, lvolumes, hr_volume_t, iter) { + if (iter->svc_id == svc_id) { + rvol = iter; + break; + } + } + + fibril_rwlock_read_unlock(&hr_volumes_lock); + return rvol; +} + +errno_t hr_remove_volume(service_id_t svc_id) +{ + HR_DEBUG("hr_remove_volume(): (%" PRIun ")\n", svc_id); + + errno_t rc; + + fibril_rwlock_write_lock(&hr_volumes_lock); + list_foreach(hr_volumes, lvolumes, hr_volume_t, vol) { + if (vol->svc_id == svc_id) { + int open_cnt = atomic_load_explicit(&vol->open_cnt, + memory_order_relaxed); + /* + * The "atomicity" of this if condition is provided + * by the write lock - no new bd connection can + * come, because we need to get the bd_srvs_t from + * volume, which we get from the list. + * (see hr_client_conn() in hr.c) + */ + if (open_cnt > 0) { + fibril_rwlock_write_unlock(&hr_volumes_lock); + return EBUSY; + } + list_remove(&vol->lvolumes); + fibril_rwlock_write_unlock(&hr_volumes_lock); + + hr_destroy_vol_struct(vol); + + rc = loc_service_unregister(hr_srv, svc_id); + return rc; + } + } + + fibril_rwlock_write_unlock(&hr_volumes_lock); + return ENOENT; +} errno_t hr_init_devs(hr_volume_t *vol) { @@ -418,5 +565,407 @@ void hr_mark_vol_state_dirty(hr_volume_t *vol) atomic_store(&vol->state_dirty, true); } +struct svc_id_linked { + link_t link; + service_id_t svc_id; + hr_metadata_t *md; + bool inited; + bool md_present; +}; + +static errno_t hr_add_svc_linked_to_list(list_t *list, service_id_t svc_id, + bool inited, hr_metadata_t *md) +{ + errno_t rc = EOK; + struct svc_id_linked *to_add; + + to_add = malloc(sizeof(struct svc_id_linked)); + if (to_add == NULL) { + rc = ENOMEM; + goto error; + } + to_add->svc_id = svc_id; + to_add->inited = inited; + + if (md != NULL) { + to_add->md = malloc(sizeof(hr_metadata_t)); + if (to_add->md == NULL) { + rc = ENOMEM; + goto error; + } + to_add->md_present = true; + memcpy(to_add->md, md, sizeof(*md)); + } else { + to_add->md_present = false; + } + + list_append(&to_add->link, list); + +error: + return rc; +} + +static void free_svc_id_linked(struct svc_id_linked *p) +{ + if (p->md_present) + free(p->md); + free(p); +} + +static void free_svc_id_list(list_t *list) +{ + struct svc_id_linked *dev_id; + while (!list_empty(list)) { + dev_id = list_pop(list, struct svc_id_linked, link); + free_svc_id_linked(dev_id); + } +} + +static errno_t hr_fill_disk_part_svcs_list(list_t *list) +{ + errno_t rc; + size_t disk_count; + service_id_t *disk_svcs = NULL; + vbd_t *vbd = NULL; + + rc = vbd_create(&vbd); + if (rc != EOK) + goto error; + + rc = vbd_get_disks(vbd, &disk_svcs, &disk_count); + if (rc != EOK) + goto error; + + for (size_t i = 0; i < disk_count; i++) { + vbd_disk_info_t disk_info; + rc = vbd_disk_info(vbd, disk_svcs[i], &disk_info); + if (rc != EOK) + goto error; + + if (disk_info.ltype == lt_none) { + rc = hr_add_svc_linked_to_list(list, disk_svcs[i], false, NULL); + if (rc != EOK) + goto error; + } else { + size_t part_count; + service_id_t *part_ids = NULL; + rc = vbd_label_get_parts(vbd, disk_svcs[i], &part_ids, &part_count); + if (rc != EOK) + goto error; + + for (size_t j = 0; j < part_count; j++) { + vbd_part_info_t part_info; + rc = vbd_part_get_info(vbd, part_ids[j], &part_info); + if (rc != EOK) { + free(part_ids); + goto error; + } + + rc = hr_add_svc_linked_to_list(list, + part_info.svc_id, false, NULL); + if (rc != EOK) { + free(part_ids); + goto error; + } + } + + free(part_ids); + } + } + + free(disk_svcs); + vbd_destroy(vbd); + return EOK; +error: + free_svc_id_list(list); + if (disk_svcs != NULL) + free(disk_svcs); + vbd_destroy(vbd); + + return rc; +} + +static errno_t block_init_dev_list(list_t *list) +{ + list_foreach_safe(*list, cur_link, next_link) { + struct svc_id_linked *iter; + iter = list_get_instance(cur_link, struct svc_id_linked, link); + + if (iter->inited) + continue; + + errno_t rc = block_init(iter->svc_id); + + /* already used as an extent of active volume */ + /* XXX: figure out how it is with hotspares too */ + if (rc == EEXIST) { + list_remove(cur_link); + free_svc_id_linked(iter); + continue; + } + + if (rc != EOK) + return rc; + + iter->inited = true; + } + + return EOK; +} + +static void block_fini_dev_list(list_t *list) +{ + list_foreach(*list, link, struct svc_id_linked, iter) { + if (iter->inited) { + block_fini(iter->svc_id); + iter->inited = false; + } + } +} + +static errno_t hr_util_get_matching_md_svcs_list(list_t *rlist, list_t *devlist, + service_id_t svc_id, hr_metadata_t *md_main) +{ + errno_t rc = EOK; + + list_foreach(*devlist, link, struct svc_id_linked, iter) { + if (iter->svc_id == svc_id) + continue; + void *md_block; + hr_metadata_t md; + rc = hr_get_metadata_block(iter->svc_id, &md_block); + if (rc != EOK) + goto error; + hr_decode_metadata_from_block(md_block, &md); + + free(md_block); + + if (!hr_valid_md_magic(&md)) + continue; + + if (memcmp(md_main->uuid, md.uuid, HR_UUID_LEN) != 0) + continue; + + /* + * XXX: can I assume bsize and everything is fine when + * UUID matches? + */ + + rc = hr_add_svc_linked_to_list(rlist, iter->svc_id, true, &md); + if (rc != EOK) + goto error; + } + + return EOK; +error: + free_svc_id_list(rlist); + return rc; +} + +static errno_t hr_util_assemble_from_matching_list(list_t *list) +{ + HR_DEBUG("%s()", __func__); + + errno_t rc = EOK; + + hr_metadata_t *main_md = NULL; + size_t max_counter_val = 0; + + list_foreach(*list, link, struct svc_id_linked, iter) { + hr_metadata_dump(iter->md); + if (iter->md->counter >= max_counter_val) { + max_counter_val = iter->md->counter; + main_md = iter->md; + } + } + + assert(main_md != NULL); + + hr_volume_t *vol; + rc = hr_create_vol_struct(&vol, (hr_level_t)main_md->level); + if (rc != EOK) + goto error; + + vol->nblocks = main_md->nblocks; + vol->data_blkno = main_md->data_blkno; + vol->truncated_blkno = main_md->truncated_blkno; + vol->data_offset = main_md->data_offset; + vol->counter = main_md->counter; + vol->metadata_version = main_md->version; + vol->extent_no = main_md->extent_no; + vol->level = main_md->level; + vol->layout = main_md->layout; + vol->strip_size = main_md->strip_size; + vol->bsize = main_md->bsize; + memcpy(vol->devname, main_md->devname, HR_DEVNAME_LEN); + + list_foreach(*list, link, struct svc_id_linked, iter) { + vol->extents[iter->md->index].svc_id = iter->svc_id; + if (iter->md->counter == max_counter_val) + vol->extents[iter->md->index].status = HR_EXT_ONLINE; + else + vol->extents[iter->md->index].status = HR_EXT_INVALID; + } + + rc = vol->hr_ops.create(vol); + if (rc != EOK) + goto error; + + fibril_rwlock_write_lock(&hr_volumes_lock); + + list_foreach(hr_volumes, lvolumes, hr_volume_t, other) { + uint8_t *our_uuid = vol->in_mem_md->uuid; + uint8_t *other_uuid = other->in_mem_md->uuid; + if (memcmp(our_uuid, other_uuid, HR_UUID_LEN) == 0) { + rc = EEXIST; + fibril_rwlock_write_unlock(&hr_volumes_lock); + goto error; + } + } + + /* + * XXX: register it here + * ... if it fails on EEXIST try different name... like + 1 on the end + */ + + list_append(&vol->lvolumes, &hr_volumes); + + fibril_rwlock_write_unlock(&hr_volumes_lock); + + return EOK; +error: + hr_destroy_vol_struct(vol); + return rc; +} + +errno_t hr_util_try_auto_assemble(size_t *rassembled_cnt) +{ + HR_DEBUG("%s()", __func__); + + /* + * scan partitions or disks: + * + * When we find a metadata block with valid + * magic, take UUID and try to find other matching + * UUIDs. + * + * We ignore extents that are a part of already + * active volumes. (even when the counter is lower + * on active volumes... XXX: use timestamp as initial counter value + * when assembling, or writing dirty metadata?) + */ + + size_t asm_cnt = 0; + errno_t rc; + list_t dev_id_list; + + list_initialize(&dev_id_list); + rc = hr_fill_disk_part_svcs_list(&dev_id_list); + if (rc != EOK) + goto error; + + rc = block_init_dev_list(&dev_id_list); + if (rc != EOK) + goto error; + + struct svc_id_linked *iter; + while (!list_empty(&dev_id_list)) { + iter = list_pop(&dev_id_list, struct svc_id_linked, link); + + printf("svc_id: %lu\n", iter->svc_id); + + void *metadata_block; + hr_metadata_t metadata; + + rc = hr_get_metadata_block(iter->svc_id, &metadata_block); + if (rc != EOK) + goto error; + + hr_decode_metadata_from_block(metadata_block, &metadata); + + free(metadata_block); + + if (!hr_valid_md_magic(&metadata)) { + printf("BAD magic\n"); + block_fini(iter->svc_id); + free_svc_id_linked(iter); + continue; + } + + hr_metadata_dump(&metadata); + + char *svc_name = NULL; + rc = loc_service_get_name(iter->svc_id, &svc_name); + if (rc != EOK) + goto error; + + HR_DEBUG("found valid metadata on %s, " + "will try to match other extents\n", svc_name); + + free(svc_name); + + list_t matching_svcs_list; + list_initialize(&matching_svcs_list); + + rc = hr_util_get_matching_md_svcs_list(&matching_svcs_list, + &dev_id_list, iter->svc_id, &metadata); + if (rc != EOK) + goto error; + + /* add current iter to list as well */ + rc = hr_add_svc_linked_to_list(&matching_svcs_list, + iter->svc_id, true, &metadata); + if (rc != EOK) { + free_svc_id_list(&matching_svcs_list); + goto error; + } + + /* remove matching list members from dev_id_list */ + list_foreach(matching_svcs_list, link, struct svc_id_linked, + iter2) { + printf("matching svc_id: %lu\n", iter2->svc_id); + struct svc_id_linked *to_remove; + list_foreach_safe(dev_id_list, cur_link, next_link) { + to_remove = list_get_instance(cur_link, + struct svc_id_linked, link); + if (to_remove->svc_id == iter2->svc_id) { + list_remove(cur_link); + free_svc_id_linked(to_remove); + } + } + } + + rc = hr_util_assemble_from_matching_list(&matching_svcs_list); + switch (rc) { + case EOK: + asm_cnt++; + break; + case EEXIST: + /* + * A race is detected this way, because we don't want + * to hold the hr_volumes list lock for a long time, + * for all assembly attempts. XXX: discuss... + */ + rc = EOK; + break; + default: + block_fini_dev_list(&matching_svcs_list); + free_svc_id_list(&matching_svcs_list); + goto error; + } + + free_svc_id_list(&matching_svcs_list); + } + +error: + if (rassembled_cnt != NULL) + *rassembled_cnt = asm_cnt; + + block_fini_dev_list(&dev_id_list); + free_svc_id_list(&dev_id_list); + + return rc; +} + /** @} */ diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index 46294ff392..debd55d199 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -50,23 +50,33 @@ #define HR_ERROR(format, ...) \ log_msg(LOG_DEFAULT, LVL_ERROR, format, ##__VA_ARGS__) -extern errno_t hr_init_devs(hr_volume_t *); -extern void hr_fini_devs(hr_volume_t *); -extern errno_t hr_register_volume(hr_volume_t *); -extern errno_t hr_check_devs(hr_volume_t *, uint64_t *, size_t *); -extern errno_t hr_check_ba_range(hr_volume_t *, size_t, uint64_t); -extern void hr_add_ba_offset(hr_volume_t *, uint64_t *); -extern void hr_update_ext_status(hr_volume_t *, size_t, hr_ext_status_t); -extern void hr_update_hotspare_status(hr_volume_t *, size_t, hr_ext_status_t); -extern void hr_update_vol_status(hr_volume_t *, hr_vol_status_t); -extern void hr_update_ext_svc_id(hr_volume_t *, size_t, service_id_t); -extern void hr_update_hotspare_svc_id(hr_volume_t *, size_t, service_id_t); -extern void hr_sync_all_extents(hr_volume_t *); -extern size_t hr_count_extents(hr_volume_t *, hr_ext_status_t); -extern hr_range_lock_t *hr_range_lock_acquire(hr_volume_t *, uint64_t, + +extern errno_t hr_create_vol_struct(hr_volume_t **, hr_level_t); +extern void hr_destroy_vol_struct(hr_volume_t *); +extern hr_volume_t *hr_get_volume(service_id_t); +extern errno_t hr_remove_volume(service_id_t); +extern errno_t hr_init_devs(hr_volume_t *); +extern void hr_fini_devs(hr_volume_t *); +extern errno_t hr_register_volume(hr_volume_t *); +extern errno_t hr_check_devs(hr_volume_t *, uint64_t *, size_t *); +extern errno_t hr_check_ba_range(hr_volume_t *, size_t, uint64_t); +extern void hr_add_ba_offset(hr_volume_t *, uint64_t *); +extern void hr_update_ext_status(hr_volume_t *, size_t, + hr_ext_status_t); +extern void hr_update_hotspare_status(hr_volume_t *, size_t, + hr_ext_status_t); +extern void hr_update_vol_status(hr_volume_t *, hr_vol_status_t); +extern void hr_update_ext_svc_id(hr_volume_t *, size_t, + service_id_t); +extern void hr_update_hotspare_svc_id(hr_volume_t *, size_t, + service_id_t); +extern void hr_sync_all_extents(hr_volume_t *); +extern size_t hr_count_extents(hr_volume_t *, hr_ext_status_t); +extern void hr_mark_vol_state_dirty(hr_volume_t *); +extern void hr_range_lock_release(hr_range_lock_t *); +extern hr_range_lock_t *hr_range_lock_acquire(hr_volume_t *, uint64_t, uint64_t); -extern void hr_range_lock_release(hr_range_lock_t *); -extern void hr_mark_vol_state_dirty(hr_volume_t *); +extern errno_t hr_util_try_auto_assemble(size_t *); #endif diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index afce33b6db..5a2918a877 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -41,14 +41,17 @@ #include #include #include +#include #include "fge.h" +#include "superblock.h" #define NAME "hr" #define HR_STRIP_SIZE DATA_XFER_LIMIT struct hr_volume; typedef struct hr_volume hr_volume_t; +typedef struct hr_metadata hr_metadata_t; typedef struct hr_ops { errno_t (*create)(hr_volume_t *); @@ -68,10 +71,15 @@ typedef struct hr_volume { fibril_mutex_t range_lock_list_lock; /* range locks list lock */ hr_fpool_t *fge; /* fibril pool */ + uint32_t metadata_version; /* XXX: yet unused */ + + hr_metadata_t *in_mem_md; /* TODO: implement */ + /* invariants */ size_t extent_no; /* number of extents */ size_t bsize; /* block size */ uint64_t nblocks; /* no. of all usable blocks */ + uint64_t truncated_blkno; /* blkno per extent */ uint64_t data_blkno; /* no. of user usable blocks */ uint64_t data_offset; /* user data offset in blocks */ uint32_t strip_size; /* strip size */ @@ -90,13 +98,9 @@ typedef struct hr_volume { _Atomic bool state_dirty; /* dirty state */ - /* - * XXX: unportable for 32-bit? - * - * Add macros for locking or atomic increment depending - * on the platform? - */ + /* XXX: atomic_uint_least64_t? */ _Atomic uint64_t rebuild_blk; /* rebuild position */ + _Atomic int open_cnt; /* open/close() counter */ uint64_t counter; /* TODO: metadata syncing */ hr_vol_status_t status; /* volume status */ } hr_volume_t; From 0437dd5148b4e03bb092fa8045c444b7592576d2 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sat, 29 Mar 2025 00:37:53 +0100 Subject: [PATCH 154/324] hr: util.c: block_fini() hotspares --- uspace/srv/bd/hr/util.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index d2af955369..3b2693ace6 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -249,6 +249,14 @@ void hr_fini_devs(hr_volume_t *vol) block_fini(vol->extents[i].svc_id); } } + + for (i = 0; i < vol->hotspare_no; i++) { + if (vol->hotspares[i].svc_id != 0) { + HR_DEBUG("hr_fini_devs(): block_fini() on (%lu)\n", + vol->hotspares[i].svc_id); + block_fini(vol->hotspares[i].svc_id); + } + } } errno_t hr_register_volume(hr_volume_t *vol) From 7a80c63a95d433b1d28299842a2a0ae1f5190b8e Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sat, 29 Mar 2025 00:40:33 +0100 Subject: [PATCH 155/324] hr: raid{0,1,5}.c: increment open() count --- uspace/srv/bd/hr/raid0.c | 10 ++++++++++ uspace/srv/bd/hr/raid1.c | 14 ++++++++++++-- uspace/srv/bd/hr/raid5.c | 14 ++++++++++++-- 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index 8f3b9c6fa9..81f63b527e 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -132,12 +132,22 @@ void hr_raid0_status_event(hr_volume_t *vol) static errno_t hr_raid0_bd_open(bd_srvs_t *bds, bd_srv_t *bd) { HR_DEBUG("%s()", __func__); + + hr_volume_t *vol = bd->srvs->sarg; + + atomic_fetch_add_explicit(&vol->open_cnt, 1, memory_order_relaxed); + return EOK; } static errno_t hr_raid0_bd_close(bd_srv_t *bd) { HR_DEBUG("%s()", __func__); + + hr_volume_t *vol = bd->srvs->sarg; + + atomic_fetch_sub_explicit(&vol->open_cnt, 1, memory_order_relaxed); + return EOK; } diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 14bdb8a053..9152479ed2 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -177,13 +177,23 @@ errno_t hr_raid1_add_hotspare(hr_volume_t *vol, service_id_t hotspare) static errno_t hr_raid1_bd_open(bd_srvs_t *bds, bd_srv_t *bd) { - HR_DEBUG("hr_bd_open()\n"); + HR_DEBUG("%s()", __func__); + + hr_volume_t *vol = bd->srvs->sarg; + + atomic_fetch_add_explicit(&vol->open_cnt, 1, memory_order_relaxed); + return EOK; } static errno_t hr_raid1_bd_close(bd_srv_t *bd) { - HR_DEBUG("hr_bd_close()\n"); + HR_DEBUG("%s()", __func__); + + hr_volume_t *vol = bd->srvs->sarg; + + atomic_fetch_sub_explicit(&vol->open_cnt, 1, memory_order_relaxed); + return EOK; } diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index b8112db0dc..7b9d13c6d1 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -195,13 +195,23 @@ errno_t hr_raid5_add_hotspare(hr_volume_t *vol, service_id_t hotspare) static errno_t hr_raid5_bd_open(bd_srvs_t *bds, bd_srv_t *bd) { - HR_DEBUG("hr_bd_open()\n"); + HR_DEBUG("%s()\n", __func__); + + hr_volume_t *vol = bd->srvs->sarg; + + atomic_fetch_add_explicit(&vol->open_cnt, 1, memory_order_relaxed); + return EOK; } static errno_t hr_raid5_bd_close(bd_srv_t *bd) { - HR_DEBUG("hr_bd_close()\n"); + HR_DEBUG("%s()\n", __func__); + + hr_volume_t *vol = bd->srvs->sarg; + + atomic_fetch_sub_explicit(&vol->open_cnt, 1, memory_order_relaxed); + return EOK; } From 8a65373df328e6a673879d93b1743a90286f567b Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sat, 29 Mar 2025 12:50:54 +0100 Subject: [PATCH 156/324] hr: move registering out of specific RAIDs --- uspace/srv/bd/hr/hr.c | 8 ++++++++ uspace/srv/bd/hr/raid0.c | 6 +----- uspace/srv/bd/hr/raid1.c | 6 +----- uspace/srv/bd/hr/raid5.c | 8 ++------ uspace/srv/bd/hr/util.c | 7 +++++++ 5 files changed, 19 insertions(+), 16 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 24ab11c58b..810a223963 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -143,6 +143,10 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) if (!assemble) { for (i = 0; i < cfg->dev_no; i++) { if (cfg->devs[i] == 0) { + /* + * XXX: own error codes, no need to log this... + * its user error not service error + */ HR_ERROR("missing device provided for array " "creation, aborting"); free(cfg); @@ -204,6 +208,10 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) if (rc != EOK) goto error; + rc = hr_register_volume(new_volume); + if (rc != EOK) + goto error; + fibril_rwlock_write_lock(&hr_volumes_lock); list_append(&new_volume->lvolumes, &hr_volumes); fibril_rwlock_write_unlock(&hr_volumes_lock); diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index 81f63b527e..e2edbb0910 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -81,8 +81,6 @@ static bd_ops_t hr_raid0_bd_ops = { errno_t hr_raid0_create(hr_volume_t *new_volume) { - errno_t rc; - assert(new_volume->level == HR_LVL_0); if (new_volume->extent_no < 2) { @@ -98,9 +96,7 @@ errno_t hr_raid0_create(hr_volume_t *new_volume) new_volume->hr_bds.ops = &hr_raid0_bd_ops; new_volume->hr_bds.sarg = new_volume; - rc = hr_register_volume(new_volume); - - return rc; + return EOK; } errno_t hr_raid0_init(hr_volume_t *vol) diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 9152479ed2..cbfe229797 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -90,8 +90,6 @@ static bd_ops_t hr_raid1_bd_ops = { errno_t hr_raid1_create(hr_volume_t *new_volume) { - errno_t rc; - assert(new_volume->level == HR_LVL_1); if (new_volume->extent_no < 2) { @@ -113,9 +111,7 @@ errno_t hr_raid1_create(hr_volume_t *new_volume) if (state == HR_VOL_FAULTY || state == HR_VOL_NONE) return EINVAL; - rc = hr_register_volume(new_volume); - - return rc; + return EOK; } errno_t hr_raid1_init(hr_volume_t *vol) diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 7b9d13c6d1..97853001b8 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -92,8 +92,6 @@ static bd_ops_t hr_raid5_bd_ops = { errno_t hr_raid5_create(hr_volume_t *new_volume) { - errno_t rc; - assert(new_volume->level == HR_LVL_5 || new_volume->level == HR_LVL_4); if (new_volume->extent_no < 3) { @@ -103,7 +101,7 @@ errno_t hr_raid5_create(hr_volume_t *new_volume) fibril_rwlock_write_lock(&new_volume->states_lock); - rc = hr_raid5_update_vol_status(new_volume); + errno_t rc = hr_raid5_update_vol_status(new_volume); if (rc != EOK) { fibril_rwlock_write_unlock(&new_volume->states_lock); return rc; @@ -113,11 +111,9 @@ errno_t hr_raid5_create(hr_volume_t *new_volume) new_volume->hr_bds.ops = &hr_raid5_bd_ops; new_volume->hr_bds.sarg = new_volume; - rc = hr_register_volume(new_volume); - fibril_rwlock_write_unlock(&new_volume->states_lock); - return rc; + return EOK; } errno_t hr_raid5_init(hr_volume_t *vol) diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 3b2693ace6..d8afcd2390 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -834,7 +834,14 @@ static errno_t hr_util_assemble_from_matching_list(list_t *list) /* * XXX: register it here * ... if it fails on EEXIST try different name... like + 1 on the end + * + * TODO: discuss */ + rc = hr_register_volume(vol); + if (rc != EOK) { + fibril_rwlock_write_unlock(&hr_volumes_lock); + goto error; + } list_append(&vol->lvolumes, &hr_volumes); From 56214383f0fb815ff5ebce810ca4c912eef5ca52 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sat, 29 Mar 2025 13:09:58 +0100 Subject: [PATCH 157/324] hr: util: hr_util_add_hotspare() --- uspace/srv/bd/hr/raid1.c | 30 +----------------------------- uspace/srv/bd/hr/raid5.c | 29 ++++++----------------------- uspace/srv/bd/hr/util.c | 32 ++++++++++++++++++++++++++++++++ uspace/srv/bd/hr/util.h | 1 + 4 files changed, 40 insertions(+), 52 deletions(-) diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index cbfe229797..2d8a756c90 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -144,27 +144,7 @@ errno_t hr_raid1_add_hotspare(hr_volume_t *vol, service_id_t hotspare) { HR_DEBUG("%s()", __func__); - errno_t rc = EOK; - - fibril_mutex_lock(&vol->hotspare_lock); - - if (vol->hotspare_no >= HR_MAX_HOTSPARES) { - HR_ERROR("hr_raid1_add_hotspare(): cannot add more hotspares " - "to \"%s\"\n", vol->devname); - rc = ELIMIT; - goto error; - } - - size_t hs_idx = vol->hotspare_no; - - vol->hotspare_no++; - - hr_update_hotspare_svc_id(vol, hs_idx, hotspare); - hr_update_hotspare_status(vol, hs_idx, HR_EXT_HOTSPARE); - - hr_mark_vol_state_dirty(vol); -error: - fibril_mutex_unlock(&vol->hotspare_lock); + errno_t rc = hr_util_add_hotspare(vol, hotspare); hr_raid1_update_vol_status(vol); @@ -655,14 +635,6 @@ static errno_t swap_hs(hr_volume_t *vol, size_t bad, size_t hs) service_id_t faulty_svc_id = vol->extents[bad].svc_id; service_id_t hs_svc_id = vol->hotspares[hs].svc_id; - /* TODO: if rc != EOK, try next hotspare */ - errno_t rc = block_init(hs_svc_id); - if (rc != EOK) { - HR_ERROR("hr_raid1_rebuild(): initing hotspare (%lu) failed\n", - hs_svc_id); - return rc; - } - hr_update_ext_svc_id(vol, bad, hs_svc_id); hr_update_ext_status(vol, bad, HR_EXT_HOTSPARE); diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 97853001b8..25772adb54 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -149,23 +149,13 @@ void hr_raid5_status_event(hr_volume_t *vol) errno_t hr_raid5_add_hotspare(hr_volume_t *vol, service_id_t hotspare) { - HR_DEBUG("hr_raid5_add_hotspare()\n"); + HR_DEBUG("%s()", __func__); fibril_mutex_lock(&vol->lock); - fibril_mutex_lock(&vol->hotspare_lock); - - if (vol->hotspare_no >= HR_MAX_HOTSPARES) { - HR_ERROR("hr_raid5_add_hotspare(): cannot add more hotspares " - "to \"%s\"\n", vol->devname); - fibril_mutex_unlock(&vol->lock); - return ELIMIT; - } - vol->hotspares[vol->hotspare_no].svc_id = hotspare; - - vol->hotspare_no++; - - hr_update_hotspare_status(vol, vol->hotspare_no - 1, HR_EXT_HOTSPARE); + errno_t rc = hr_util_add_hotspare(vol, hotspare); + if (rc != EOK) + goto end; /* * If the volume is degraded, start rebuild right away. @@ -183,10 +173,10 @@ errno_t hr_raid5_add_hotspare(hr_volume_t *vol, service_id_t hotspare) fibril_detach(fib); } - fibril_mutex_unlock(&vol->hotspare_lock); +end: fibril_mutex_unlock(&vol->lock); - return EOK; + return rc; } static errno_t hr_raid5_bd_open(bd_srvs_t *bds, bd_srv_t *bd) @@ -769,13 +759,6 @@ static errno_t hr_raid5_rebuild(void *arg) hr_extent_t *rebuild_ext = &vol->extents[bad]; - rc = block_init(rebuild_ext->svc_id); - if (rc != EOK) { - HR_ERROR("hr_raid5_rebuild(): initing (%lu) failed, " - "aborting rebuild\n", rebuild_ext->svc_id); - goto end; - } - HR_DEBUG("hr_raid5_rebuild(): starting rebuild on (%lu)\n", rebuild_ext->svc_id); diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index d8afcd2390..973b71d5b4 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -982,5 +982,37 @@ errno_t hr_util_try_auto_assemble(size_t *rassembled_cnt) return rc; } +errno_t hr_util_add_hotspare(hr_volume_t *vol, service_id_t hotspare) +{ + HR_DEBUG("%s()", __func__); + + errno_t rc = EOK; + + fibril_mutex_lock(&vol->hotspare_lock); + + if (vol->hotspare_no >= HR_MAX_HOTSPARES) { + HR_ERROR("%s(): cannot add more hotspares " + "to \"%s\"\n", __func__, vol->devname); + rc = ELIMIT; + goto end; + } + + rc = block_init(hotspare); + if (rc != EOK) + goto end; + + size_t hs_idx = vol->hotspare_no; + + vol->hotspare_no++; + + hr_update_hotspare_svc_id(vol, hs_idx, hotspare); + hr_update_hotspare_status(vol, hs_idx, HR_EXT_HOTSPARE); + + hr_mark_vol_state_dirty(vol); +end: + fibril_mutex_unlock(&vol->hotspare_lock); + return rc; +} + /** @} */ diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index debd55d199..dbd1fe47d2 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -77,6 +77,7 @@ extern void hr_range_lock_release(hr_range_lock_t *); extern hr_range_lock_t *hr_range_lock_acquire(hr_volume_t *, uint64_t, uint64_t); extern errno_t hr_util_try_auto_assemble(size_t *); +extern errno_t hr_util_add_hotspare(hr_volume_t *, service_id_t); #endif From 49de61c9e92744460e132ae5f47509c10860aeb7 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sat, 29 Mar 2025 14:57:12 +0100 Subject: [PATCH 158/324] hr: util.c: fix hr_register_volume() --- uspace/srv/bd/hr/util.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 973b71d5b4..038c7ee74f 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -276,7 +276,8 @@ errno_t hr_register_volume(hr_volume_t *vol) if (rc != EOK) { HR_ERROR("unable to register device \"%s\": %s\n", fullname, str_error(rc)); - goto error; + free(fullname); + return rc; } rc = loc_category_get_id("raid", &cat_id, IPC_FLAG_BLOCKING); @@ -294,7 +295,11 @@ errno_t hr_register_volume(hr_volume_t *vol) } vol->svc_id = new_id; + + free(fullname); + return EOK; error: + rc = loc_service_unregister(hr_srv, new_id); free(fullname); return rc; } From d946c276f2d4f5f802edae75a06c2d1d60e8099c Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sat, 29 Mar 2025 14:58:15 +0100 Subject: [PATCH 159/324] hr: initialize and populate in memory metadata --- uspace/srv/bd/hr/superblock.c | 2 ++ uspace/srv/bd/hr/util.c | 22 +++++++++++++++++----- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index cbe5b68a45..40a03c69fe 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -88,6 +88,8 @@ errno_t hr_write_meta_to_vol(hr_volume_t *vol) goto error; } + + memcpy(vol->in_mem_md, metadata, sizeof(hr_metadata_t)); error: free(metadata); return rc; diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 038c7ee74f..12f5ee8dce 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -108,6 +108,13 @@ errno_t hr_create_vol_struct(hr_volume_t **rvol, hr_level_t level) goto error; } + vol->in_mem_md = calloc(1, sizeof(hr_metadata_t)); + if (vol->in_mem_md == NULL) { + free(vol->fge); + rc = ENOMEM; + goto error; + } + vol->status = HR_VOL_NONE; for (size_t i = 0; i < HR_MAX_EXTENTS; ++i) @@ -812,6 +819,8 @@ static errno_t hr_util_assemble_from_matching_list(list_t *list) vol->bsize = main_md->bsize; memcpy(vol->devname, main_md->devname, HR_DEVNAME_LEN); + memcpy(vol->in_mem_md, main_md, sizeof(hr_metadata_t)); + list_foreach(*list, link, struct svc_id_linked, iter) { vol->extents[iter->md->index].svc_id = iter->svc_id; if (iter->md->counter == max_counter_val) @@ -840,6 +849,13 @@ static errno_t hr_util_assemble_from_matching_list(list_t *list) * XXX: register it here * ... if it fails on EEXIST try different name... like + 1 on the end * + * or have metadata edit utility as a part of hrctl..., or create + * the original name + 4 random characters, tell the user that the device + * was created with this new name, and add a option to hrctl to rename + * an active array, and then write the new dirty metadata... + * + * or just refuse to assemble a name that is already used... + * * TODO: discuss */ rc = hr_register_volume(vol); @@ -892,8 +908,6 @@ errno_t hr_util_try_auto_assemble(size_t *rassembled_cnt) while (!list_empty(&dev_id_list)) { iter = list_pop(&dev_id_list, struct svc_id_linked, link); - printf("svc_id: %lu\n", iter->svc_id); - void *metadata_block; hr_metadata_t metadata; @@ -906,13 +920,12 @@ errno_t hr_util_try_auto_assemble(size_t *rassembled_cnt) free(metadata_block); if (!hr_valid_md_magic(&metadata)) { - printf("BAD magic\n"); block_fini(iter->svc_id); free_svc_id_linked(iter); continue; } - hr_metadata_dump(&metadata); + /* hr_metadata_dump(&metadata); */ char *svc_name = NULL; rc = loc_service_get_name(iter->svc_id, &svc_name); @@ -943,7 +956,6 @@ errno_t hr_util_try_auto_assemble(size_t *rassembled_cnt) /* remove matching list members from dev_id_list */ list_foreach(matching_svcs_list, link, struct svc_id_linked, iter2) { - printf("matching svc_id: %lu\n", iter2->svc_id); struct svc_id_linked *to_remove; list_foreach_safe(dev_id_list, cur_link, next_link) { to_remove = list_get_instance(cur_link, From 2e7df2e50d670bbbef5ec0966cef7715bd4052fc Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sat, 29 Mar 2025 14:59:08 +0100 Subject: [PATCH 160/324] hr: superblock.c: fix UUID memcpy() --- uspace/srv/bd/hr/superblock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index 40a03c69fe..37845ed2ae 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -76,7 +76,7 @@ errno_t hr_write_meta_to_vol(hr_volume_t *vol) goto error; /* XXX: for now we just copy byte by byte as "encoding" */ - memcpy(metadata->uuid, &uuid, sizeof(HR_UUID_LEN)); + memcpy(metadata->uuid, &uuid, HR_UUID_LEN); /* uuid_encode(&uuid, metadata->uuid); */ for (i = 0; i < vol->extent_no; i++) { From 7e8c0e7bc120a237a1a6f91d2beffce5c69d485c Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sat, 29 Mar 2025 14:59:46 +0100 Subject: [PATCH 161/324] hr: superblock.c: remove UUID generation for each extent --- uspace/srv/bd/hr/superblock.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index 37845ed2ae..6297db49bd 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -101,7 +101,6 @@ errno_t hr_write_meta_to_ext(hr_volume_t *vol, size_t ext) errno_t rc; hr_metadata_t *metadata; - uuid_t uuid; /* XXX: use scratchpad */ metadata = calloc(1, HR_META_SIZE * vol->bsize); @@ -114,11 +113,6 @@ errno_t hr_write_meta_to_ext(hr_volume_t *vol, size_t ext) metadata->index = host2uint32_t_le(ext); - rc = uuid_generate(&uuid); - if (rc != EOK) - goto error; - uuid_encode(&uuid, metadata->uuid); - rc = block_write_direct(vol->extents[ext].svc_id, HR_META_OFF, HR_META_SIZE, metadata); if (rc != EOK) From 1a285186b88b49dd4c8b2dc2752470b5603ff486 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sat, 29 Mar 2025 15:00:25 +0100 Subject: [PATCH 162/324] hr: superblock.c: fix bsize decoding --- uspace/srv/bd/hr/superblock.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index 6297db49bd..190b21c534 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -325,6 +325,8 @@ void hr_decode_metadata_from_block(void *block, hr_metadata_t *metadata) memcpy(metadata->magic, scratch_md.magic, HR_MAGIC_SIZE); memcpy(metadata->uuid, scratch_md.uuid, HR_UUID_LEN); + /* uuid_decode((uint8_t *)scratch_md.uuid, (uuid_t *)metadata->uuid); */ + metadata->nblocks = uint64_t_le2host(scratch_md.nblocks); metadata->data_blkno = uint64_t_le2host(scratch_md.data_blkno); metadata->truncated_blkno = uint64_t_le2host( @@ -337,7 +339,7 @@ void hr_decode_metadata_from_block(void *block, hr_metadata_t *metadata) metadata->level = uint32_t_le2host(scratch_md.level); metadata->layout = uint32_t_le2host(scratch_md.layout); metadata->strip_size = uint32_t_le2host(scratch_md.strip_size); - metadata->bsize = uint64_t_le2host(scratch_md.bsize); + metadata->bsize = uint32_t_le2host(scratch_md.bsize); memcpy(metadata->devname, scratch_md.devname, HR_DEVNAME_LEN); } @@ -362,6 +364,7 @@ void hr_metadata_dump(hr_metadata_t *metadata) printf("\tlevel: %u\n", metadata->level); printf("\tlayout: %u\n", metadata->layout); printf("\tstrip_size: %u\n", metadata->strip_size); + printf("\tbsize: %u\n", metadata->bsize); printf("\tdevname: %s\n", metadata->devname); } From d082801827048a1134fdb37be2c167c9a6991e34 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sat, 29 Mar 2025 15:04:37 +0100 Subject: [PATCH 163/324] hr: refactor manual assembly --- uspace/app/hrctl/hrctl.c | 46 +++++++---- uspace/lib/device/include/hr.h | 3 +- uspace/lib/device/src/hr.c | 42 +++++++++- uspace/srv/bd/hr/hr.c | 145 ++++++++++++++++++++------------- uspace/srv/bd/hr/util.c | 24 +++++- uspace/srv/bd/hr/util.h | 3 +- 6 files changed, 185 insertions(+), 78 deletions(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index 1d2aab2c5c..74ae070e14 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -61,7 +61,7 @@ static const char usage_str[] = " -D, --destroy destroy/disassemble an active array\n" " -F, --fail-extent fail an extent, use with -D and set it before\n" " -c, --create=NAME create new array\n" - " -a, --assemble=NAME assemble from specified extents\n" + " -a, --assemble try to assemble from specified extents\n" " -n non-zero number of devices\n" " -l, --level=LEVEL set the RAID level,\n" " valid values: 0, 1, 4, 5\n" @@ -77,9 +77,9 @@ static const char usage_str[] = " hrctl --create hr0 -0 -n 2 devices/\\hw\\0 devices/\\hw\\1\n" " - creates new mirroring RAID device named /hr0 consisting\n" " of 2 drives\n" - " hrctl --assemble hr0 -n 2 devices/\\hw\\0 devices/\\hw\\1\n" - " - assembles RAID device named /hr0 consisting of 2 drives,\n" - " that were previously in an array\n" + " hrctl --assemble -n 2 devices/\\hw\\0 devices/\\hw\\1\n" + " - assembles RAID devices from specified extents,\n" + " that were previously in an (active) array\n" " hrctl devices/hr0 --hotspare=devices/disk10\n" " - adds \"devices/disk10\" as hotspare extent\n" " hrctl -F 0 -D devices/hr0\n" @@ -90,7 +90,7 @@ static const char usage_str[] = static struct option const long_options[] = { { "help", no_argument, 0, 'h' }, { "status", no_argument, 0, 's' }, - { "assemble", required_argument, 0, 'a' }, + { "assemble", no_argument, 0, 'a' }, { "create", required_argument, 0, 'c' }, { "level", required_argument, 0, 'l' }, { "create-file", required_argument, 0, 'C' }, @@ -252,7 +252,7 @@ int main(int argc, char **argv) optind = 0; while (c != -1) { - c = getopt_long(argc, argv, "hsC:c:Aa:l:0145Ln:D:F:H:", + c = getopt_long(argc, argv, "hsC:c:Aal:0145Ln:D:F:H:", long_options, NULL); switch (c) { case 's': @@ -293,12 +293,20 @@ int main(int argc, char **argv) } return rc; case 'a': - if (str_size(optarg) > sizeof(cfg->devname) - 1) { - printf("hrctl: device name too long\n"); - free(cfg); - return 1; - } - str_cpy(cfg->devname, sizeof(cfg->devname), optarg); + /* + * XXX: redo this, no devname, only svc ids... + * + * find some other way to rename the arrays..., + * + * some metadata editation tool... something like + * fdisk but can only change devnames on inactive + * extents... + */ + + /* + * XXX: remake whole parsing, don't allow -a + * to have any levels set or anything + */ assemble = true; break; case 'D': @@ -413,11 +421,19 @@ int main(int argc, char **argv) } if (create) { - rc = hr_create(hr, cfg, false); + rc = hr_create(hr, cfg); printf("hrctl: hr_create() rc: %s\n", str_error(rc)); } else if (assemble) { - rc = hr_create(hr, cfg, true); - printf("hrctl: hr_assemble() rc: %s\n", str_error(rc)); + size_t assembled_cnt = 0; + rc = hr_assemble(hr, cfg, &assembled_cnt); + if (rc != EOK) { + /* XXX: here have own error codes */ + printf("hrctl: auto assemble rc: %s\n", str_error(rc)); + } else { + printf("hrctl: auto assembled %lu volumes\n", + assembled_cnt); + } + } end: diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index 9be5b0b5b3..aa842bd7de 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -116,7 +116,8 @@ typedef struct hr_vol_info { extern errno_t hr_sess_init(hr_t **); extern void hr_sess_destroy(hr_t *); -extern errno_t hr_create(hr_t *, hr_config_t *, bool); +extern errno_t hr_create(hr_t *, hr_config_t *); +extern errno_t hr_assemble(hr_t *, hr_config_t *, size_t *); extern errno_t hr_auto_assemble(size_t *); extern errno_t hr_stop(const char *, long); extern errno_t hr_add_hotspare(service_id_t, service_id_t); diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index 7bbbdc7dde..7b4fcc968a 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Miroslav Cimerman + * Copyright (c) 2025 Miroslav Cimerman * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -87,7 +87,7 @@ void hr_sess_destroy(hr_t *hr) free(hr); } -errno_t hr_create(hr_t *hr, hr_config_t *hr_config, bool assemble) +errno_t hr_create(hr_t *hr, hr_config_t *hr_config) { errno_t rc, retval; async_exch_t *exch; @@ -97,7 +97,7 @@ errno_t hr_create(hr_t *hr, hr_config_t *hr_config, bool assemble) if (exch == NULL) return EINVAL; - req = async_send_0(exch, assemble ? HR_ASSEMBLE : HR_CREATE, NULL); + req = async_send_0(exch, HR_CREATE, NULL); rc = async_data_write_start(exch, hr_config, sizeof(hr_config_t)); if (rc != EOK) { @@ -114,6 +114,42 @@ errno_t hr_create(hr_t *hr, hr_config_t *hr_config, bool assemble) return EOK; } +errno_t hr_assemble(hr_t *hr, hr_config_t *hr_config, size_t *rassembled_cnt) +{ + errno_t rc; + async_exch_t *exch; + aid_t req; + size_t assembled_cnt; + + exch = async_exchange_begin(hr->sess); + if (exch == NULL) + return EINVAL; + + req = async_send_0(exch, HR_ASSEMBLE, NULL); + + rc = async_data_write_start(exch, hr_config, sizeof(hr_config_t)); + if (rc != EOK) { + async_exchange_end(exch); + async_forget(req); + return rc; + } + + rc = async_data_read_start(exch, &assembled_cnt, sizeof(size_t)); + if (rc != EOK) { + async_exchange_end(exch); + async_forget(req); + return rc; + } + + async_exchange_end(exch); + async_wait_for(req, &rc); + + if (rassembled_cnt != NULL) + *rassembled_cnt = assembled_cnt; + + return rc; +} + errno_t hr_auto_assemble(size_t *rassembled_cnt) { hr_t *hr; diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 810a223963..07302d39ca 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -78,28 +78,86 @@ static void hr_auto_assemble_srv(ipc_call_t *icall) } if (size != sizeof(size_t)) { + async_answer_0(&call, EINVAL); async_answer_0(icall, EINVAL); return; } - rc = hr_util_try_auto_assemble(&assembled_cnt); - if (rc != EOK) { - async_answer_0(&call, rc); - async_answer_0(icall, rc); + rc = hr_util_try_assemble(NULL, &assembled_cnt); + if (rc != EOK) + goto error; + + rc = async_data_read_finalize(&call, &assembled_cnt, size); + if (rc != EOK) + goto error; + + async_answer_0(icall, EOK); + return; +error: + async_answer_0(&call, rc); + async_answer_0(icall, rc); +} + +static void hr_assemble_srv(ipc_call_t *icall) +{ + HR_DEBUG("%s()", __func__); + + errno_t rc; + size_t size, assembled_cnt; + hr_config_t *cfg; + ipc_call_t call; + + if (!async_data_write_receive(&call, &size)) { + async_answer_0(&call, EREFUSED); + async_answer_0(icall, EREFUSED); return; } - rc = async_data_read_finalize(&call, &assembled_cnt, size); - if (rc != EOK) { - async_answer_0(&call, rc); - async_answer_0(icall, rc); + if (size != sizeof(hr_config_t)) { + async_answer_0(&call, EINVAL); + async_answer_0(icall, EINVAL); + return; + } + + cfg = calloc(1, sizeof(hr_config_t)); + if (cfg == NULL) { + async_answer_0(&call, ENOMEM); + async_answer_0(icall, ENOMEM); + return; + } + + rc = async_data_write_finalize(&call, cfg, size); + if (rc != EOK) + goto error; + + if (!async_data_read_receive(&call, &size)) { + async_answer_0(icall, EREFUSED); return; } + if (size != sizeof(size_t)) { + async_answer_0(icall, EINVAL); + return; + } + + rc = hr_util_try_assemble(cfg, &assembled_cnt); + if (rc != EOK) + goto error; + + rc = async_data_read_finalize(&call, &assembled_cnt, size); + if (rc != EOK) + goto error; + + free(cfg); async_answer_0(icall, EOK); + return; +error: + free(cfg); + async_answer_0(&call, rc); + async_answer_0(icall, rc); } -static void hr_create_srv(ipc_call_t *icall, bool assemble) +static void hr_create_srv(ipc_call_t *icall) { HR_DEBUG("%s()", __func__); @@ -140,19 +198,17 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) * If there was a missing device provided * for creation of a new array, abort */ - if (!assemble) { - for (i = 0; i < cfg->dev_no; i++) { - if (cfg->devs[i] == 0) { - /* - * XXX: own error codes, no need to log this... - * its user error not service error - */ - HR_ERROR("missing device provided for array " - "creation, aborting"); - free(cfg); - async_answer_0(icall, EINVAL); - return; - } + for (i = 0; i < cfg->dev_no; i++) { + if (cfg->devs[i] == 0) { + /* + * XXX: own error codes, no need to log this... + * its user error not service error + */ + HR_ERROR("missing device provided for array " + "creation, aborting"); + free(cfg); + async_answer_0(icall, EINVAL); + return; } } @@ -169,6 +225,7 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) new_volume->level = cfg->level; new_volume->extent_no = cfg->dev_no; + /* XXX: do proper initing ... */ rc = hr_init_devs(new_volume); if (rc != EOK) { free(cfg); @@ -177,32 +234,13 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) return; } - if (assemble) { - if (cfg->level != HR_LVL_UNKNOWN) - HR_DEBUG("level manually set when assembling, ingoring"); - new_volume->level = HR_LVL_UNKNOWN; - } - - if (assemble) { - /* just bsize needed for reading metadata later */ - rc = hr_check_devs(new_volume, NULL, &new_volume->bsize); - if (rc != EOK) - goto error; - - rc = hr_fill_vol_from_meta(new_volume); - if (rc != EOK) - goto error; - } - - if (!assemble) { - new_volume->hr_ops.init(new_volume); - if (rc != EOK) - goto error; + new_volume->hr_ops.init(new_volume); + if (rc != EOK) + goto error; - rc = hr_write_meta_to_vol(new_volume); - if (rc != EOK) - goto error; - } + rc = hr_write_meta_to_vol(new_volume); + if (rc != EOK) + goto error; rc = new_volume->hr_ops.create(new_volume); if (rc != EOK) @@ -216,13 +254,8 @@ static void hr_create_srv(ipc_call_t *icall, bool assemble) list_append(&new_volume->lvolumes, &hr_volumes); fibril_rwlock_write_unlock(&hr_volumes_lock); - if (assemble) { - HR_DEBUG("assembled volume \"%s\" (%" PRIun ")\n", - new_volume->devname, new_volume->svc_id); - } else { - HR_DEBUG("created volume \"%s\" (%" PRIun ")\n", - new_volume->devname, new_volume->svc_id); - } + HR_DEBUG("created volume \"%s\" (%" PRIun ")\n", new_volume->devname, + new_volume->svc_id); free(cfg); async_answer_0(icall, rc); @@ -389,10 +422,10 @@ static void hr_ctl_conn(ipc_call_t *icall, void *arg) switch (method) { case HR_CREATE: - hr_create_srv(&call, false); + hr_create_srv(&call); break; case HR_ASSEMBLE: - hr_create_srv(&call, true); + hr_assemble_srv(&call); break; case HR_AUTO_ASSEMBLE: hr_auto_assemble_srv(&call); diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 12f5ee8dce..be993b1a46 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -874,7 +874,22 @@ static errno_t hr_util_assemble_from_matching_list(list_t *list) return rc; } -errno_t hr_util_try_auto_assemble(size_t *rassembled_cnt) +static errno_t hr_fill_svcs_list_from_cfg(hr_config_t *cfg, list_t *list) +{ + errno_t rc = EOK; + for (size_t i = 0; i < cfg->dev_no; ++i) { + rc = hr_add_svc_linked_to_list(list, cfg->devs[i], false, NULL); + if (rc != EOK) + goto error; + } + + return EOK; +error: + free_svc_id_list(list); + return rc; +} + +errno_t hr_util_try_assemble(hr_config_t *cfg, size_t *rassembled_cnt) { HR_DEBUG("%s()", __func__); @@ -896,7 +911,12 @@ errno_t hr_util_try_auto_assemble(size_t *rassembled_cnt) list_t dev_id_list; list_initialize(&dev_id_list); - rc = hr_fill_disk_part_svcs_list(&dev_id_list); + + if (cfg == NULL) + rc = hr_fill_disk_part_svcs_list(&dev_id_list); + else + rc = hr_fill_svcs_list_from_cfg(cfg, &dev_id_list); + if (rc != EOK) goto error; diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index dbd1fe47d2..b3d06d0ebb 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -37,6 +37,7 @@ #define _HR_UTIL_H #include +#include #include #include "var.h" @@ -76,7 +77,7 @@ extern void hr_mark_vol_state_dirty(hr_volume_t *); extern void hr_range_lock_release(hr_range_lock_t *); extern hr_range_lock_t *hr_range_lock_acquire(hr_volume_t *, uint64_t, uint64_t); -extern errno_t hr_util_try_auto_assemble(size_t *); +extern errno_t hr_util_try_assemble(hr_config_t *, size_t *); extern errno_t hr_util_add_hotspare(hr_volume_t *, service_id_t); #endif From 746e636585e0d3bd3069437de2f444739c3aa1a7 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 30 Mar 2025 18:17:37 +0200 Subject: [PATCH 164/324] hr: add comments to raid init() --- uspace/srv/bd/hr/raid0.c | 9 +++++++++ uspace/srv/bd/hr/raid1.c | 9 +++++++++ uspace/srv/bd/hr/raid5.c | 11 ++++++++++- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index e2edbb0910..03fc3ac61e 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -99,6 +99,9 @@ errno_t hr_raid0_create(hr_volume_t *new_volume) return EOK; } +/* + * Called only once in volume's lifetime. + */ errno_t hr_raid0_init(hr_volume_t *vol) { errno_t rc; @@ -113,6 +116,12 @@ errno_t hr_raid0_init(hr_volume_t *vol) vol->nblocks = total_blkno; vol->bsize = bsize; + /* + * XXX: according to bsize set the data_offset... + * + * also can change this depending on level, like + * RAID5 might try to put data at 64K boundary + */ vol->data_offset = HR_DATA_OFF; vol->data_blkno = vol->nblocks - (vol->data_offset * vol->extent_no); vol->strip_size = HR_STRIP_SIZE; diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 2d8a756c90..51e02df5a5 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -114,6 +114,9 @@ errno_t hr_raid1_create(hr_volume_t *new_volume) return EOK; } +/* + * Called only once in volume's lifetime. + */ errno_t hr_raid1_init(hr_volume_t *vol) { errno_t rc; @@ -128,6 +131,12 @@ errno_t hr_raid1_init(hr_volume_t *vol) vol->nblocks = total_blkno / vol->extent_no; vol->bsize = bsize; + /* + * XXX: according to bsize set the data_offset... + * + * also can change this depending on level, like + * RAID5 might try to put data at 64K boundary + */ vol->data_offset = HR_DATA_OFF; vol->data_blkno = vol->nblocks - vol->data_offset; vol->strip_size = 0; diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 25772adb54..10e2adb21a 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Miroslav Cimerman + * Copyright (c) 2025 Miroslav Cimerman * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -116,6 +116,9 @@ errno_t hr_raid5_create(hr_volume_t *new_volume) return EOK; } +/* + * Called only once in volume's lifetime. + */ errno_t hr_raid5_init(hr_volume_t *vol) { errno_t rc; @@ -130,6 +133,12 @@ errno_t hr_raid5_init(hr_volume_t *vol) vol->nblocks = total_blkno; vol->bsize = bsize; + /* + * XXX: according to bsize set the data_offset... + * + * also can change this depending on level, like + * RAID5 might try to put data at 64K boundary + */ vol->data_offset = HR_DATA_OFF; vol->data_blkno = vol->nblocks - (vol->data_offset * vol->extent_no) - (vol->nblocks / vol->extent_no); From 6d0fc1180b67061b8a08ad0dadb0ce418098023c Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 30 Mar 2025 21:38:58 +0200 Subject: [PATCH 165/324] hr: style: align structures, function prototypes --- uspace/srv/bd/hr/fge.c | 89 ++++++++-------- uspace/srv/bd/hr/fge.h | 14 +-- uspace/srv/bd/hr/hr.c | 192 ++++++++++++++++++---------------- uspace/srv/bd/hr/io.h | 16 +-- uspace/srv/bd/hr/raid0.c | 37 +++---- uspace/srv/bd/hr/raid1.c | 48 ++++----- uspace/srv/bd/hr/raid5.c | 52 ++++----- uspace/srv/bd/hr/superblock.h | 4 +- uspace/srv/bd/hr/util.c | 31 ++++-- 9 files changed, 253 insertions(+), 230 deletions(-) diff --git a/uspace/srv/bd/hr/fge.c b/uspace/srv/bd/hr/fge.c index aae010d4ed..7d4ad94099 100644 --- a/uspace/srv/bd/hr/fge.c +++ b/uspace/srv/bd/hr/fge.c @@ -52,62 +52,63 @@ #include "fge.h" +/* forward declarations */ struct fge_fibril_data; typedef struct fge_fibril_data fge_fibril_data_t; struct wu_queue; typedef struct wu_queue wu_queue_t; -static void *hr_fpool_make_storage(hr_fpool_t *, ssize_t *); -static void hr_fpool_group_epilogue(hr_fpool_t *); -static errno_t fge_fibril(void *); -static errno_t wu_queue_init(wu_queue_t *, size_t); -static void wu_queue_push(wu_queue_t *, fge_fibril_data_t *); -static void wu_queue_pop(wu_queue_t *, fge_fibril_data_t *); -static ssize_t hr_fpool_get_free_slot(hr_fpool_t *); - -typedef struct fge_fibril_data { - hr_wu_t wu; /* user-provided work unit fcn pointer */ - void *arg; - hr_fgroup_t *group; - ssize_t memslot; /* index to pool bitmap slot */ -} fge_fibril_data_t; - -typedef struct wu_queue { - fibril_mutex_t lock; - fibril_condvar_t not_empty; - fibril_condvar_t not_full; - fge_fibril_data_t *fexecs; +static void *hr_fpool_make_storage(hr_fpool_t *, ssize_t *); +static void hr_fpool_group_epilogue(hr_fpool_t *); +static errno_t fge_fibril(void *); +static errno_t wu_queue_init(wu_queue_t *, size_t); +static void wu_queue_push(wu_queue_t *, fge_fibril_data_t *); +static void wu_queue_pop(wu_queue_t *, fge_fibril_data_t *); +static ssize_t hr_fpool_get_free_slot(hr_fpool_t *); + +struct fge_fibril_data { + hr_wu_t wu; /* work unit function pointer */ + void *arg; /* work unit function argument */ + hr_fgroup_t *group; /* back-pointer to group */ + ssize_t memslot; /* index to pool bitmap slot */ +}; + +struct wu_queue { + fibril_mutex_t lock; + fibril_condvar_t not_empty; + fibril_condvar_t not_full; + fge_fibril_data_t *fexecs; /* circ-buf memory */ circ_buf_t cbuf; -} wu_queue_t; +}; struct hr_fpool { - fibril_mutex_t lock; + fibril_mutex_t lock; + bitmap_t bitmap; /* memory slot bitmap */ + wu_queue_t queue; + fid_t *fibrils; + uint8_t *wu_storage; /* pre-allocated pool storage */ + size_t fibril_cnt; + size_t max_wus; + size_t active_groups; + bool stop; + size_t wu_size; + size_t wu_storage_free_count; fibril_condvar_t all_wus_done; - bitmap_t bitmap; - wu_queue_t queue; - fid_t *fibrils; - uint8_t *wu_storage; - size_t fibril_cnt; - size_t max_wus; - size_t active_groups; - bool stop; - size_t wu_size; - size_t wu_storage_free_count; }; struct hr_fgroup { - hr_fpool_t *pool; - size_t wu_cnt; /* total wu count */ - size_t submitted; - size_t reserved_cnt; /* no. of reserved wu storage slots */ - size_t reserved_avail; - size_t *memslots; /* indices to pool bitmap */ - void *own_mem; - size_t own_used; - errno_t final_errno; - size_t finished_okay; - size_t finished_fail; - fibril_mutex_t lock; + hr_fpool_t *pool; /* back-pointer to pool */ + size_t wu_cnt; /* upper bound of work units */ + size_t submitted; /* number of submitted jobs */ + size_t reserved_cnt; /* no. of reserved wu storage slots */ + size_t reserved_avail; + size_t *memslots; /* indices to pool bitmap */ + void *own_mem; /* own allocated memory */ + size_t own_used; /* own memory slots used counter */ + errno_t final_errno; /* agreggated errno */ + size_t finished_okay; /* no. of wus that ended with EOK */ + size_t finished_fail; /* no. of wus that ended with != EOK */ + fibril_mutex_t lock; fibril_condvar_t all_done; }; diff --git a/uspace/srv/bd/hr/fge.h b/uspace/srv/bd/hr/fge.h index a2652ea751..1deca8743f 100644 --- a/uspace/srv/bd/hr/fge.h +++ b/uspace/srv/bd/hr/fge.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Miroslav Cimerman + * Copyright (c) 2025 Miroslav Cimerman * Copyright (c) 2024 Vojtech Horky * All rights reserved. * @@ -47,12 +47,12 @@ typedef struct hr_fgroup hr_fgroup_t; typedef errno_t (*hr_wu_t)(void *); -extern hr_fpool_t *hr_fpool_create(size_t, size_t, size_t); -extern void hr_fpool_destroy(hr_fpool_t *); -extern hr_fgroup_t *hr_fgroup_create(hr_fpool_t *, size_t); -extern void *hr_fgroup_alloc(hr_fgroup_t *); -extern void hr_fgroup_submit(hr_fgroup_t *, hr_wu_t, void *); -extern errno_t hr_fgroup_wait(hr_fgroup_t *, size_t *, size_t *); +extern hr_fpool_t *hr_fpool_create(size_t, size_t, size_t); +extern void hr_fpool_destroy(hr_fpool_t *); +extern hr_fgroup_t *hr_fgroup_create(hr_fpool_t *, size_t); +extern void *hr_fgroup_alloc(hr_fgroup_t *); +extern void hr_fgroup_submit(hr_fgroup_t *, hr_wu_t, void *); +extern errno_t hr_fgroup_wait(hr_fgroup_t *, size_t *, size_t *); #endif diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 07302d39ca..3ef20c3898 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -57,44 +57,126 @@ #include "util.h" #include "var.h" +static void hr_assemble_srv(ipc_call_t *); +static void hr_auto_assemble_srv(ipc_call_t *); +static void hr_stop_srv(ipc_call_t *); +static void hr_add_hotspare_srv(ipc_call_t *); +static void hr_print_status_srv(ipc_call_t *); +static void hr_ctl_conn(ipc_call_t *, void *); +static void hr_client_conn(ipc_call_t *, void *); + loc_srv_t *hr_srv; list_t hr_volumes; fibril_rwlock_t hr_volumes_lock; static service_id_t ctl_sid; -static void hr_auto_assemble_srv(ipc_call_t *icall) +static void hr_create_srv(ipc_call_t *icall) { HR_DEBUG("%s()", __func__); errno_t rc; - size_t size; - size_t assembled_cnt = 0; + size_t i, size; + hr_config_t *cfg; + hr_volume_t *new_volume; ipc_call_t call; - if (!async_data_read_receive(&call, &size)) { + if (!async_data_write_receive(&call, &size)) { + async_answer_0(&call, EREFUSED); async_answer_0(icall, EREFUSED); return; } - if (size != sizeof(size_t)) { + if (size != sizeof(hr_config_t)) { async_answer_0(&call, EINVAL); async_answer_0(icall, EINVAL); return; } - rc = hr_util_try_assemble(NULL, &assembled_cnt); + cfg = calloc(1, sizeof(hr_config_t)); + if (cfg == NULL) { + async_answer_0(&call, ENOMEM); + async_answer_0(icall, ENOMEM); + return; + } + + rc = async_data_write_finalize(&call, cfg, size); + if (rc != EOK) { + free(cfg); + async_answer_0(&call, rc); + async_answer_0(icall, rc); + return; + } + + /* + * If there was a missing device provided + * for creation of a new array, abort + */ + for (i = 0; i < cfg->dev_no; i++) { + if (cfg->devs[i] == 0) { + /* + * XXX: own error codes, no need to log this... + * its user error not service error + */ + HR_ERROR("missing device provided for array " + "creation, aborting"); + free(cfg); + async_answer_0(icall, EINVAL); + return; + } + } + + rc = hr_create_vol_struct(&new_volume, cfg->level); + if (rc != EOK) { + free(cfg); + async_answer_0(icall, rc); + return; + } + + str_cpy(new_volume->devname, HR_DEVNAME_LEN, cfg->devname); + for (i = 0; i < cfg->dev_no; i++) + new_volume->extents[i].svc_id = cfg->devs[i]; + new_volume->level = cfg->level; + new_volume->extent_no = cfg->dev_no; + + /* XXX: do proper initing ... */ + rc = hr_init_devs(new_volume); + if (rc != EOK) { + free(cfg); + free(new_volume); + async_answer_0(icall, rc); + return; + } + + new_volume->hr_ops.init(new_volume); if (rc != EOK) goto error; - rc = async_data_read_finalize(&call, &assembled_cnt, size); + rc = hr_write_meta_to_vol(new_volume); if (rc != EOK) goto error; - async_answer_0(icall, EOK); + rc = new_volume->hr_ops.create(new_volume); + if (rc != EOK) + goto error; + + rc = hr_register_volume(new_volume); + if (rc != EOK) + goto error; + + fibril_rwlock_write_lock(&hr_volumes_lock); + list_append(&new_volume->lvolumes, &hr_volumes); + fibril_rwlock_write_unlock(&hr_volumes_lock); + + HR_DEBUG("created volume \"%s\" (%" PRIun ")\n", new_volume->devname, + new_volume->svc_id); + + free(cfg); + async_answer_0(icall, rc); return; error: - async_answer_0(&call, rc); + free(cfg); + hr_destroy_vol_struct(new_volume); async_answer_0(icall, rc); } @@ -157,112 +239,38 @@ static void hr_assemble_srv(ipc_call_t *icall) async_answer_0(icall, rc); } -static void hr_create_srv(ipc_call_t *icall) +static void hr_auto_assemble_srv(ipc_call_t *icall) { HR_DEBUG("%s()", __func__); errno_t rc; - size_t i, size; - hr_config_t *cfg; - hr_volume_t *new_volume; + size_t size; + size_t assembled_cnt = 0; ipc_call_t call; - if (!async_data_write_receive(&call, &size)) { - async_answer_0(&call, EREFUSED); + if (!async_data_read_receive(&call, &size)) { async_answer_0(icall, EREFUSED); return; } - if (size != sizeof(hr_config_t)) { + if (size != sizeof(size_t)) { async_answer_0(&call, EINVAL); async_answer_0(icall, EINVAL); return; } - cfg = calloc(1, sizeof(hr_config_t)); - if (cfg == NULL) { - async_answer_0(&call, ENOMEM); - async_answer_0(icall, ENOMEM); - return; - } - - rc = async_data_write_finalize(&call, cfg, size); - if (rc != EOK) { - free(cfg); - async_answer_0(&call, rc); - async_answer_0(icall, rc); - return; - } - - /* - * If there was a missing device provided - * for creation of a new array, abort - */ - for (i = 0; i < cfg->dev_no; i++) { - if (cfg->devs[i] == 0) { - /* - * XXX: own error codes, no need to log this... - * its user error not service error - */ - HR_ERROR("missing device provided for array " - "creation, aborting"); - free(cfg); - async_answer_0(icall, EINVAL); - return; - } - } - - rc = hr_create_vol_struct(&new_volume, cfg->level); - if (rc != EOK) { - free(cfg); - async_answer_0(icall, rc); - return; - } - - str_cpy(new_volume->devname, HR_DEVNAME_LEN, cfg->devname); - for (i = 0; i < cfg->dev_no; i++) - new_volume->extents[i].svc_id = cfg->devs[i]; - new_volume->level = cfg->level; - new_volume->extent_no = cfg->dev_no; - - /* XXX: do proper initing ... */ - rc = hr_init_devs(new_volume); - if (rc != EOK) { - free(cfg); - free(new_volume); - async_answer_0(icall, rc); - return; - } - - new_volume->hr_ops.init(new_volume); - if (rc != EOK) - goto error; - - rc = hr_write_meta_to_vol(new_volume); - if (rc != EOK) - goto error; - - rc = new_volume->hr_ops.create(new_volume); + rc = hr_util_try_assemble(NULL, &assembled_cnt); if (rc != EOK) goto error; - rc = hr_register_volume(new_volume); + rc = async_data_read_finalize(&call, &assembled_cnt, size); if (rc != EOK) goto error; - fibril_rwlock_write_lock(&hr_volumes_lock); - list_append(&new_volume->lvolumes, &hr_volumes); - fibril_rwlock_write_unlock(&hr_volumes_lock); - - HR_DEBUG("created volume \"%s\" (%" PRIun ")\n", new_volume->devname, - new_volume->svc_id); - - free(cfg); - async_answer_0(icall, rc); + async_answer_0(icall, EOK); return; error: - free(cfg); - hr_destroy_vol_struct(new_volume); + async_answer_0(&call, rc); async_answer_0(icall, rc); } diff --git a/uspace/srv/bd/hr/io.h b/uspace/srv/bd/hr/io.h index fc45478071..424e9e0066 100644 --- a/uspace/srv/bd/hr/io.h +++ b/uspace/srv/bd/hr/io.h @@ -39,14 +39,14 @@ #include "var.h" typedef struct hr_io { - hr_bd_op_type_t type; - uint64_t ba; - uint64_t cnt; - size_t extent; - void *data_read; - const void *data_write; - hr_volume_t *vol; - void (*state_callback)(hr_volume_t *, size_t, errno_t); + hr_bd_op_type_t type; + uint64_t ba; + uint64_t cnt; + size_t extent; + void *data_read; + const void *data_write; + hr_volume_t *vol; + void (*state_callback)(hr_volume_t *, size_t, errno_t); } hr_io_t; errno_t hr_io_worker(void *); diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index 03fc3ac61e..881a7f9ec5 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -52,33 +52,34 @@ #include "util.h" #include "var.h" -extern loc_srv_t *hr_srv; - -static void hr_raid0_update_vol_status(hr_volume_t *); -static errno_t hr_raid0_bd_op(hr_bd_op_type_t, bd_srv_t *, aoff64_t, size_t, +static void hr_raid0_update_vol_status(hr_volume_t *); +static void raid0_state_callback(hr_volume_t *, size_t, errno_t); +static errno_t hr_raid0_bd_op(hr_bd_op_type_t, bd_srv_t *, aoff64_t, size_t, void *, const void *, size_t); /* bdops */ -static errno_t hr_raid0_bd_open(bd_srvs_t *, bd_srv_t *); -static errno_t hr_raid0_bd_close(bd_srv_t *); -static errno_t hr_raid0_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, +static errno_t hr_raid0_bd_open(bd_srvs_t *, bd_srv_t *); +static errno_t hr_raid0_bd_close(bd_srv_t *); +static errno_t hr_raid0_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, size_t); -static errno_t hr_raid0_bd_sync_cache(bd_srv_t *, aoff64_t, size_t); -static errno_t hr_raid0_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, +static errno_t hr_raid0_bd_sync_cache(bd_srv_t *, aoff64_t, size_t); +static errno_t hr_raid0_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, const void *, size_t); -static errno_t hr_raid0_bd_get_block_size(bd_srv_t *, size_t *); -static errno_t hr_raid0_bd_get_num_blocks(bd_srv_t *, aoff64_t *); +static errno_t hr_raid0_bd_get_block_size(bd_srv_t *, size_t *); +static errno_t hr_raid0_bd_get_num_blocks(bd_srv_t *, aoff64_t *); static bd_ops_t hr_raid0_bd_ops = { - .open = hr_raid0_bd_open, - .close = hr_raid0_bd_close, - .sync_cache = hr_raid0_bd_sync_cache, - .read_blocks = hr_raid0_bd_read_blocks, - .write_blocks = hr_raid0_bd_write_blocks, - .get_block_size = hr_raid0_bd_get_block_size, - .get_num_blocks = hr_raid0_bd_get_num_blocks + .open = hr_raid0_bd_open, + .close = hr_raid0_bd_close, + .sync_cache = hr_raid0_bd_sync_cache, + .read_blocks = hr_raid0_bd_read_blocks, + .write_blocks = hr_raid0_bd_write_blocks, + .get_block_size = hr_raid0_bd_get_block_size, + .get_num_blocks = hr_raid0_bd_get_num_blocks }; +extern loc_srv_t *hr_srv; + errno_t hr_raid0_create(hr_volume_t *new_volume) { assert(new_volume->level == HR_LVL_0); diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 51e02df5a5..272366f5ab 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -53,41 +53,41 @@ #include "util.h" #include "var.h" -extern loc_srv_t *hr_srv; - -static void hr_raid1_update_vol_status(hr_volume_t *); -static void hr_raid1_ext_state_callback(hr_volume_t *, size_t, errno_t); -static size_t hr_raid1_count_good_extents(hr_volume_t *, uint64_t, size_t, +static void hr_raid1_update_vol_status(hr_volume_t *); +static void hr_raid1_ext_state_callback(hr_volume_t *, size_t, errno_t); +static size_t hr_raid1_count_good_extents(hr_volume_t *, uint64_t, size_t, uint64_t); -static errno_t hr_raid1_bd_op(hr_bd_op_type_t, bd_srv_t *, aoff64_t, size_t, +static errno_t hr_raid1_bd_op(hr_bd_op_type_t, bd_srv_t *, aoff64_t, size_t, void *, const void *, size_t); -static errno_t hr_raid1_rebuild(void *); -static errno_t init_rebuild(hr_volume_t *, size_t *); -static errno_t swap_hs(hr_volume_t *, size_t, size_t); -static errno_t hr_raid1_restore_blocks(hr_volume_t *, size_t, uint64_t, size_t, +static errno_t hr_raid1_rebuild(void *); +static errno_t init_rebuild(hr_volume_t *, size_t *); +static errno_t swap_hs(hr_volume_t *, size_t, size_t); +static errno_t hr_raid1_restore_blocks(hr_volume_t *, size_t, uint64_t, size_t, void *); /* bdops */ -static errno_t hr_raid1_bd_open(bd_srvs_t *, bd_srv_t *); -static errno_t hr_raid1_bd_close(bd_srv_t *); -static errno_t hr_raid1_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, +static errno_t hr_raid1_bd_open(bd_srvs_t *, bd_srv_t *); +static errno_t hr_raid1_bd_close(bd_srv_t *); +static errno_t hr_raid1_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, size_t); -static errno_t hr_raid1_bd_sync_cache(bd_srv_t *, aoff64_t, size_t); -static errno_t hr_raid1_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, +static errno_t hr_raid1_bd_sync_cache(bd_srv_t *, aoff64_t, size_t); +static errno_t hr_raid1_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, const void *, size_t); -static errno_t hr_raid1_bd_get_block_size(bd_srv_t *, size_t *); -static errno_t hr_raid1_bd_get_num_blocks(bd_srv_t *, aoff64_t *); +static errno_t hr_raid1_bd_get_block_size(bd_srv_t *, size_t *); +static errno_t hr_raid1_bd_get_num_blocks(bd_srv_t *, aoff64_t *); static bd_ops_t hr_raid1_bd_ops = { - .open = hr_raid1_bd_open, - .close = hr_raid1_bd_close, - .sync_cache = hr_raid1_bd_sync_cache, - .read_blocks = hr_raid1_bd_read_blocks, - .write_blocks = hr_raid1_bd_write_blocks, - .get_block_size = hr_raid1_bd_get_block_size, - .get_num_blocks = hr_raid1_bd_get_num_blocks + .open = hr_raid1_bd_open, + .close = hr_raid1_bd_close, + .sync_cache = hr_raid1_bd_sync_cache, + .read_blocks = hr_raid1_bd_read_blocks, + .write_blocks = hr_raid1_bd_write_blocks, + .get_block_size = hr_raid1_bd_get_block_size, + .get_num_blocks = hr_raid1_bd_get_num_blocks }; +extern loc_srv_t *hr_srv; + errno_t hr_raid1_create(hr_volume_t *new_volume) { assert(new_volume->level == HR_LVL_1); diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 10e2adb21a..9a6ca92578 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -52,44 +52,44 @@ #include "util.h" #include "var.h" -extern loc_srv_t *hr_srv; - -static errno_t hr_raid5_vol_usable(hr_volume_t *); -static ssize_t hr_raid5_get_bad_ext(hr_volume_t *); -static errno_t hr_raid5_update_vol_status(hr_volume_t *); -static void hr_raid5_handle_extent_error(hr_volume_t *, size_t, errno_t); -static void xor(void *, const void *, size_t); -static errno_t hr_raid5_read_degraded(hr_volume_t *, uint64_t, uint64_t, +static errno_t hr_raid5_vol_usable(hr_volume_t *); +static ssize_t hr_raid5_get_bad_ext(hr_volume_t *); +static errno_t hr_raid5_update_vol_status(hr_volume_t *); +static void hr_raid5_handle_extent_error(hr_volume_t *, size_t, errno_t); +static void xor(void *, const void *, size_t); +static errno_t hr_raid5_read_degraded(hr_volume_t *, uint64_t, uint64_t, void *, size_t); -static errno_t hr_raid5_write(hr_volume_t *, uint64_t, uint64_t, aoff64_t, +static errno_t hr_raid5_write(hr_volume_t *, uint64_t, uint64_t, aoff64_t, const void *, size_t); -static errno_t hr_raid5_write_parity(hr_volume_t *, uint64_t, uint64_t, +static errno_t hr_raid5_write_parity(hr_volume_t *, uint64_t, uint64_t, uint64_t, const void *, size_t); -static errno_t hr_raid5_bd_op(hr_bd_op_type_t, bd_srv_t *, aoff64_t, size_t, +static errno_t hr_raid5_bd_op(hr_bd_op_type_t, bd_srv_t *, aoff64_t, size_t, void *, const void *, size_t); -static errno_t hr_raid5_rebuild(void *); +static errno_t hr_raid5_rebuild(void *); /* bdops */ -static errno_t hr_raid5_bd_open(bd_srvs_t *, bd_srv_t *); -static errno_t hr_raid5_bd_close(bd_srv_t *); -static errno_t hr_raid5_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, +static errno_t hr_raid5_bd_open(bd_srvs_t *, bd_srv_t *); +static errno_t hr_raid5_bd_close(bd_srv_t *); +static errno_t hr_raid5_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, size_t); -static errno_t hr_raid5_bd_sync_cache(bd_srv_t *, aoff64_t, size_t); -static errno_t hr_raid5_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, +static errno_t hr_raid5_bd_sync_cache(bd_srv_t *, aoff64_t, size_t); +static errno_t hr_raid5_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, const void *, size_t); -static errno_t hr_raid5_bd_get_block_size(bd_srv_t *, size_t *); -static errno_t hr_raid5_bd_get_num_blocks(bd_srv_t *, aoff64_t *); +static errno_t hr_raid5_bd_get_block_size(bd_srv_t *, size_t *); +static errno_t hr_raid5_bd_get_num_blocks(bd_srv_t *, aoff64_t *); static bd_ops_t hr_raid5_bd_ops = { - .open = hr_raid5_bd_open, - .close = hr_raid5_bd_close, - .sync_cache = hr_raid5_bd_sync_cache, - .read_blocks = hr_raid5_bd_read_blocks, - .write_blocks = hr_raid5_bd_write_blocks, - .get_block_size = hr_raid5_bd_get_block_size, - .get_num_blocks = hr_raid5_bd_get_num_blocks + .open = hr_raid5_bd_open, + .close = hr_raid5_bd_close, + .sync_cache = hr_raid5_bd_sync_cache, + .read_blocks = hr_raid5_bd_read_blocks, + .write_blocks = hr_raid5_bd_write_blocks, + .get_block_size = hr_raid5_bd_get_block_size, + .get_num_blocks = hr_raid5_bd_get_num_blocks }; +extern loc_srv_t *hr_srv; + errno_t hr_raid5_create(hr_volume_t *new_volume) { assert(new_volume->level == HR_LVL_5 || new_volume->level == HR_LVL_4); diff --git a/uspace/srv/bd/hr/superblock.h b/uspace/srv/bd/hr/superblock.h index 7f6c1f3f4e..e43cd9c5b0 100644 --- a/uspace/srv/bd/hr/superblock.h +++ b/uspace/srv/bd/hr/superblock.h @@ -62,8 +62,8 @@ struct hr_metadata { uint64_t truncated_blkno; /* usable blocks */ uint64_t data_offset; - uint64_t counter; /* yet unused */ - uint32_t version; /* yet unused */ + uint64_t counter; /* XXX: yet unused */ + uint32_t version; /* XXX: yet unused */ uint32_t extent_no; uint32_t index; /* index of extent in volume */ diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index be993b1a46..1bbbe62f88 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -52,11 +52,32 @@ #include "util.h" #include "var.h" +struct svc_id_linked; + +static bool hr_range_lock_overlap(hr_range_lock_t *, hr_range_lock_t *); +static errno_t hr_add_svc_linked_to_list(list_t *, service_id_t, bool, + hr_metadata_t *); +static void free_svc_id_linked(struct svc_id_linked *); +static void free_svc_id_list(list_t *); +static errno_t hr_fill_disk_part_svcs_list(list_t *); +static errno_t block_init_dev_list(list_t *); +static void block_fini_dev_list(list_t *); +static errno_t hr_util_get_matching_md_svcs_list(list_t *, list_t *, + service_id_t, hr_metadata_t *); +static errno_t hr_util_assemble_from_matching_list(list_t *); +static errno_t hr_fill_svcs_list_from_cfg(hr_config_t *, list_t *); + #define HR_RL_LIST_LOCK(vol) (fibril_mutex_lock(&vol->range_lock_list_lock)) #define HR_RL_LIST_UNLOCK(vol) \ (fibril_mutex_unlock(&vol->range_lock_list_lock)) -static bool hr_range_lock_overlap(hr_range_lock_t *, hr_range_lock_t *); +struct svc_id_linked { + link_t link; + service_id_t svc_id; + hr_metadata_t *md; + bool inited; + bool md_present; +}; extern loc_srv_t *hr_srv; extern list_t hr_volumes; @@ -585,14 +606,6 @@ void hr_mark_vol_state_dirty(hr_volume_t *vol) atomic_store(&vol->state_dirty, true); } -struct svc_id_linked { - link_t link; - service_id_t svc_id; - hr_metadata_t *md; - bool inited; - bool md_present; -}; - static errno_t hr_add_svc_linked_to_list(list_t *list, service_id_t svc_id, bool inited, hr_metadata_t *md) { From baa49290919a649d4090b465f31dc72c6d79b38a Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 31 Mar 2025 19:07:34 +0200 Subject: [PATCH 166/324] hr: extent init refactor, blkno truncation --- uspace/srv/bd/hr/hr.c | 19 +---- uspace/srv/bd/hr/raid0.c | 31 ++++---- uspace/srv/bd/hr/raid1.c | 28 +++---- uspace/srv/bd/hr/raid5.c | 31 ++++---- uspace/srv/bd/hr/util.c | 166 +++++++++++++++++++-------------------- uspace/srv/bd/hr/util.h | 6 +- uspace/srv/bd/hr/var.h | 3 - 7 files changed, 132 insertions(+), 152 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 3ef20c3898..04cb027b53 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -126,27 +126,16 @@ static void hr_create_srv(ipc_call_t *icall) } } - rc = hr_create_vol_struct(&new_volume, cfg->level); + rc = hr_create_vol_struct(&new_volume, cfg->level, cfg->devname); if (rc != EOK) { free(cfg); async_answer_0(icall, rc); return; } - str_cpy(new_volume->devname, HR_DEVNAME_LEN, cfg->devname); - for (i = 0; i < cfg->dev_no; i++) - new_volume->extents[i].svc_id = cfg->devs[i]; - new_volume->level = cfg->level; - new_volume->extent_no = cfg->dev_no; - - /* XXX: do proper initing ... */ - rc = hr_init_devs(new_volume); - if (rc != EOK) { - free(cfg); - free(new_volume); - async_answer_0(icall, rc); - return; - } + rc = hr_init_extents_from_cfg(new_volume, cfg); + if (rc != EOK) + goto error; new_volume->hr_ops.init(new_volume); if (rc != EOK) diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index 881a7f9ec5..3851a62b63 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -82,6 +82,8 @@ extern loc_srv_t *hr_srv; errno_t hr_raid0_create(hr_volume_t *new_volume) { + HR_DEBUG("%s()", __func__); + assert(new_volume->level == HR_LVL_0); if (new_volume->extent_no < 2) { @@ -105,26 +107,25 @@ errno_t hr_raid0_create(hr_volume_t *new_volume) */ errno_t hr_raid0_init(hr_volume_t *vol) { - errno_t rc; - size_t bsize; - uint64_t total_blkno; + HR_DEBUG("%s()", __func__); assert(vol->level == HR_LVL_0); - rc = hr_check_devs(vol, &total_blkno, &bsize); - if (rc != EOK) - return rc; + uint64_t truncated_blkno = vol->extents[0].blkno; + for (size_t i = 1; i < vol->extent_no; i++) { + if (vol->extents[i].blkno < truncated_blkno) + truncated_blkno = vol->extents[i].blkno; + } + + uint64_t total_blkno = truncated_blkno * vol->extent_no; + vol->truncated_blkno = truncated_blkno; vol->nblocks = total_blkno; - vol->bsize = bsize; - /* - * XXX: according to bsize set the data_offset... - * - * also can change this depending on level, like - * RAID5 might try to put data at 64K boundary - */ vol->data_offset = HR_DATA_OFF; - vol->data_blkno = vol->nblocks - (vol->data_offset * vol->extent_no); + + vol->data_blkno = total_blkno; + vol->data_blkno -= HR_META_SIZE * vol->extent_no; /* count md blocks */ + vol->strip_size = HR_STRIP_SIZE; return EOK; @@ -132,6 +133,8 @@ errno_t hr_raid0_init(hr_volume_t *vol) void hr_raid0_status_event(hr_volume_t *vol) { + HR_DEBUG("%s()", __func__); + hr_raid0_update_vol_status(vol); } diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 272366f5ab..7ff8e0f267 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -90,6 +90,8 @@ extern loc_srv_t *hr_srv; errno_t hr_raid1_create(hr_volume_t *new_volume) { + HR_DEBUG("%s()", __func__); + assert(new_volume->level == HR_LVL_1); if (new_volume->extent_no < 2) { @@ -119,26 +121,20 @@ errno_t hr_raid1_create(hr_volume_t *new_volume) */ errno_t hr_raid1_init(hr_volume_t *vol) { - errno_t rc; - size_t bsize; - uint64_t total_blkno; + HR_DEBUG("%s()", __func__); assert(vol->level == HR_LVL_1); - rc = hr_check_devs(vol, &total_blkno, &bsize); - if (rc != EOK) - return rc; + uint64_t truncated_blkno = vol->extents[0].blkno; + for (size_t i = 1; i < vol->extent_no; i++) { + if (vol->extents[i].blkno < truncated_blkno) + truncated_blkno = vol->extents[i].blkno; + } - vol->nblocks = total_blkno / vol->extent_no; - vol->bsize = bsize; - /* - * XXX: according to bsize set the data_offset... - * - * also can change this depending on level, like - * RAID5 might try to put data at 64K boundary - */ + vol->truncated_blkno = truncated_blkno; + vol->nblocks = truncated_blkno; vol->data_offset = HR_DATA_OFF; - vol->data_blkno = vol->nblocks - vol->data_offset; + vol->data_blkno = truncated_blkno - HR_META_SIZE; vol->strip_size = 0; return EOK; @@ -146,6 +142,8 @@ errno_t hr_raid1_init(hr_volume_t *vol) void hr_raid1_status_event(hr_volume_t *vol) { + HR_DEBUG("%s()", __func__); + hr_raid1_update_vol_status(vol); } diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 9a6ca92578..f09f5d9793 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -92,6 +92,8 @@ extern loc_srv_t *hr_srv; errno_t hr_raid5_create(hr_volume_t *new_volume) { + HR_DEBUG("%s()", __func__); + assert(new_volume->level == HR_LVL_5 || new_volume->level == HR_LVL_4); if (new_volume->extent_no < 3) { @@ -121,27 +123,26 @@ errno_t hr_raid5_create(hr_volume_t *new_volume) */ errno_t hr_raid5_init(hr_volume_t *vol) { - errno_t rc; - size_t bsize; - uint64_t total_blkno; + HR_DEBUG("%s()", __func__); assert(vol->level == HR_LVL_5 || vol->level == HR_LVL_4); - rc = hr_check_devs(vol, &total_blkno, &bsize); - if (rc != EOK) - return rc; + uint64_t truncated_blkno = vol->extents[0].blkno; + for (size_t i = 1; i < vol->extent_no; i++) { + if (vol->extents[i].blkno < truncated_blkno) + truncated_blkno = vol->extents[i].blkno; + } + + uint64_t total_blkno = truncated_blkno * vol->extent_no; + vol->truncated_blkno = truncated_blkno; vol->nblocks = total_blkno; - vol->bsize = bsize; - /* - * XXX: according to bsize set the data_offset... - * - * also can change this depending on level, like - * RAID5 might try to put data at 64K boundary - */ vol->data_offset = HR_DATA_OFF; - vol->data_blkno = vol->nblocks - (vol->data_offset * vol->extent_no) - - (vol->nblocks / vol->extent_no); + + vol->data_blkno = total_blkno; + vol->data_blkno -= HR_META_SIZE * vol->extent_no; /* count md blocks */ + vol->data_blkno -= truncated_blkno; /* count parity */ + vol->strip_size = HR_STRIP_SIZE; return EOK; diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 1bbbe62f88..e04d2e032c 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -83,7 +84,8 @@ extern loc_srv_t *hr_srv; extern list_t hr_volumes; extern fibril_rwlock_t hr_volumes_lock; -errno_t hr_create_vol_struct(hr_volume_t **rvol, hr_level_t level) +errno_t hr_create_vol_struct(hr_volume_t **rvol, hr_level_t level, + const char *devname) { errno_t rc; @@ -91,6 +93,7 @@ errno_t hr_create_vol_struct(hr_volume_t **rvol, hr_level_t level) if (vol == NULL) return ENOMEM; + str_cpy(vol->devname, HR_DEVNAME_LEN, devname); vol->level = level; switch (level) { @@ -138,12 +141,6 @@ errno_t hr_create_vol_struct(hr_volume_t **rvol, hr_level_t level) vol->status = HR_VOL_NONE; - for (size_t i = 0; i < HR_MAX_EXTENTS; ++i) - vol->extents[i].status = HR_EXT_MISSING; - - for (size_t i = 0; i < HR_MAX_HOTSPARES; ++i) - vol->extents[i].status = HR_EXT_MISSING; - fibril_mutex_initialize(&vol->lock); /* XXX: will remove this */ fibril_rwlock_initialize(&vol->extents_lock); @@ -231,36 +228,64 @@ errno_t hr_remove_volume(service_id_t svc_id) return ENOENT; } -errno_t hr_init_devs(hr_volume_t *vol) +errno_t hr_init_extents_from_cfg(hr_volume_t *vol, hr_config_t *cfg) { HR_DEBUG("%s()", __func__); errno_t rc; - size_t i; - hr_extent_t *extent; + size_t i, blkno, bsize; + size_t last_bsize = 0; - for (i = 0; i < vol->extent_no; i++) { - extent = &vol->extents[i]; - if (extent->svc_id == 0) { - extent->status = HR_EXT_MISSING; - continue; + for (i = 0; i < cfg->dev_no; i++) { + service_id_t svc_id = cfg->devs[i]; + if (svc_id == 0) { + rc = EINVAL; + goto error; } - HR_DEBUG("hr_init_devs(): block_init() on (%lu)\n", - extent->svc_id); - rc = block_init(extent->svc_id); - extent->status = HR_EXT_ONLINE; - + HR_DEBUG("%s(): block_init() on (%lu)\n", __func__, svc_id); + rc = block_init(svc_id); if (rc != EOK) { - HR_ERROR("hr_init_devs(): initing (%lu) failed, " - "aborting\n", extent->svc_id); - break; + HR_DEBUG("%s(): initing (%lu) failed, aborting\n", + __func__, svc_id); + goto error; + } + + rc = block_get_nblocks(svc_id, &blkno); + if (rc != EOK) + goto error; + + rc = block_get_bsize(svc_id, &bsize); + if (rc != EOK) + goto error; + + if (last_bsize != 0 && bsize != last_bsize) { + HR_DEBUG("block sizes differ\n"); + rc = EINVAL; + goto error; } + + vol->extents[i].svc_id = svc_id; + vol->extents[i].blkno = blkno; + vol->extents[i].status = HR_EXT_ONLINE; + + last_bsize = bsize; } + vol->bsize = last_bsize; + vol->extent_no = cfg->dev_no; + for (i = 0; i < HR_MAX_HOTSPARES; i++) vol->hotspares[i].status = HR_EXT_MISSING; + return EOK; + +error: + for (i = 0; i < HR_MAX_EXTENTS; i++) { + if (vol->extents[i].svc_id != 0) + block_fini(vol->extents[i].svc_id); + } + return rc; } @@ -332,64 +357,6 @@ errno_t hr_register_volume(hr_volume_t *vol) return rc; } -errno_t hr_check_devs(hr_volume_t *vol, uint64_t *rblkno, size_t *rbsize) -{ - HR_DEBUG("%s()", __func__); - - errno_t rc; - size_t i, bsize; - uint64_t nblocks; - size_t last_bsize = 0; - uint64_t last_nblocks = 0; - uint64_t total_blocks = 0; - hr_extent_t *extent; - - for (i = 0; i < vol->extent_no; i++) { - extent = &vol->extents[i]; - if (extent->status == HR_EXT_MISSING) - continue; - rc = block_get_nblocks(extent->svc_id, &nblocks); - if (rc != EOK) - goto error; - if (last_nblocks != 0 && nblocks != last_nblocks) { - HR_ERROR("number of blocks differs\n"); - rc = EINVAL; - goto error; - } - - total_blocks += nblocks; - last_nblocks = nblocks; - } - - for (i = 0; i < vol->extent_no; i++) { - extent = &vol->extents[i]; - if (extent->status == HR_EXT_MISSING) - continue; - rc = block_get_bsize(extent->svc_id, &bsize); - if (rc != EOK) - goto error; - if (last_bsize != 0 && bsize != last_bsize) { - HR_ERROR("block sizes differ\n"); - rc = EINVAL; - goto error; - } - - last_bsize = bsize; - } - - if ((bsize % 512) != 0) { - HR_ERROR("block size not multiple of 512\n"); - return EINVAL; - } - - if (rblkno != NULL) - *rblkno = total_blocks; - if (rbsize != NULL) - *rbsize = bsize; -error: - return rc; -} - errno_t hr_check_ba_range(hr_volume_t *vol, size_t cnt, uint64_t ba) { if (ba + cnt > vol->data_blkno) @@ -815,7 +782,8 @@ static errno_t hr_util_assemble_from_matching_list(list_t *list) assert(main_md != NULL); hr_volume_t *vol; - rc = hr_create_vol_struct(&vol, (hr_level_t)main_md->level); + rc = hr_create_vol_struct(&vol, (hr_level_t)main_md->level, + main_md->devname); if (rc != EOK) goto error; @@ -826,16 +794,23 @@ static errno_t hr_util_assemble_from_matching_list(list_t *list) vol->counter = main_md->counter; vol->metadata_version = main_md->version; vol->extent_no = main_md->extent_no; - vol->level = main_md->level; + /* vol->level = main_md->level; */ vol->layout = main_md->layout; vol->strip_size = main_md->strip_size; vol->bsize = main_md->bsize; - memcpy(vol->devname, main_md->devname, HR_DEVNAME_LEN); + /* memcpy(vol->devname, main_md->devname, HR_DEVNAME_LEN); */ memcpy(vol->in_mem_md, main_md, sizeof(hr_metadata_t)); list_foreach(*list, link, struct svc_id_linked, iter) { vol->extents[iter->md->index].svc_id = iter->svc_id; + + size_t blkno; + rc = block_get_nblocks(iter->svc_id, &blkno); + if (rc != EOK) + goto error; + vol->extents[iter->md->index].blkno = blkno; + if (iter->md->counter == max_counter_val) vol->extents[iter->md->index].status = HR_EXT_ONLINE; else @@ -1044,12 +1019,29 @@ errno_t hr_util_add_hotspare(hr_volume_t *vol, service_id_t hotspare) HR_ERROR("%s(): cannot add more hotspares " "to \"%s\"\n", __func__, vol->devname); rc = ELIMIT; - goto end; + goto error; } rc = block_init(hotspare); if (rc != EOK) - goto end; + goto error; + + size_t hs_blkno; + rc = block_get_nblocks(hotspare, &hs_blkno); + if (rc != EOK) { + block_fini(hotspare); + goto error; + } + + /* + * TODO: make more flexible, when will have foreign md, the calculation + * will differ, maybe something new like vol->md_hs_blkno will be enough + */ + if (hs_blkno < vol->truncated_blkno - HR_META_SIZE) { + rc = EINVAL; + block_fini(hotspare); + goto error; + } size_t hs_idx = vol->hotspare_no; @@ -1059,7 +1051,7 @@ errno_t hr_util_add_hotspare(hr_volume_t *vol, service_id_t hotspare) hr_update_hotspare_status(vol, hs_idx, HR_EXT_HOTSPARE); hr_mark_vol_state_dirty(vol); -end: +error: fibril_mutex_unlock(&vol->hotspare_lock); return rc; } diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index b3d06d0ebb..5a702b2e4a 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -52,14 +52,14 @@ log_msg(LOG_DEFAULT, LVL_ERROR, format, ##__VA_ARGS__) -extern errno_t hr_create_vol_struct(hr_volume_t **, hr_level_t); +extern errno_t hr_create_vol_struct(hr_volume_t **, hr_level_t, + const char *); extern void hr_destroy_vol_struct(hr_volume_t *); extern hr_volume_t *hr_get_volume(service_id_t); extern errno_t hr_remove_volume(service_id_t); -extern errno_t hr_init_devs(hr_volume_t *); +extern errno_t hr_init_extents_from_cfg(hr_volume_t *, hr_config_t *); extern void hr_fini_devs(hr_volume_t *); extern errno_t hr_register_volume(hr_volume_t *); -extern errno_t hr_check_devs(hr_volume_t *, uint64_t *, size_t *); extern errno_t hr_check_ba_range(hr_volume_t *, size_t, uint64_t); extern void hr_add_ba_offset(hr_volume_t *, uint64_t *); extern void hr_update_ext_status(hr_volume_t *, size_t, diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index 5a2918a877..c172349cac 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -122,9 +122,6 @@ typedef struct hr_range_lock { bool ignore; /* prot. by vol->range_lock_list_lock */ } hr_range_lock_t; -extern errno_t hr_init_devs(hr_volume_t *); -extern void hr_fini_devs(hr_volume_t *); - extern errno_t hr_raid0_create(hr_volume_t *); extern errno_t hr_raid1_create(hr_volume_t *); extern errno_t hr_raid5_create(hr_volume_t *); From a5ec4263bc4f320dbe3328b8e724f3d739c37283 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 31 Mar 2025 19:08:27 +0200 Subject: [PATCH 167/324] hr: superblock: move to last block --- uspace/srv/bd/hr/superblock.c | 24 +++++++++++++++--------- uspace/srv/bd/hr/superblock.h | 8 +++++--- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index 190b21c534..600893fcef 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -82,8 +82,8 @@ errno_t hr_write_meta_to_vol(hr_volume_t *vol) for (i = 0; i < vol->extent_no; i++) { metadata->index = host2uint32_t_le(i); - rc = block_write_direct(vol->extents[i].svc_id, HR_META_OFF, - HR_META_SIZE, metadata); + rc = block_write_direct(vol->extents[i].svc_id, + vol->extents[i].blkno - 1, HR_META_SIZE, metadata); if (rc != EOK) goto error; @@ -113,8 +113,8 @@ errno_t hr_write_meta_to_ext(hr_volume_t *vol, size_t ext) metadata->index = host2uint32_t_le(ext); - rc = block_write_direct(vol->extents[ext].svc_id, HR_META_OFF, - HR_META_SIZE, metadata); + rc = block_write_direct(vol->extents[ext].svc_id, + vol->extents[ext].blkno - 1, HR_META_SIZE, metadata); if (rc != EOK) goto error; @@ -133,7 +133,7 @@ static errno_t hr_fill_meta_from_vol(hr_volume_t *vol, hr_metadata_t *metadata) { HR_DEBUG("%s()", __func__); - size_t meta_blkno = HR_META_OFF + HR_META_SIZE; + size_t meta_blkno = HR_META_SIZE; if (vol->level != HR_LVL_1) meta_blkno *= vol->extent_no; @@ -192,6 +192,11 @@ errno_t hr_fill_vol_from_meta(hr_volume_t *vol) for (size_t i = 0; i < vol->extent_no; i++) assembly_svc_id_order[i] = vol->extents[i].svc_id; + /* + * XXX: sanitize metadata, for example if truncated_blkno <= extent.blkno + * or bsize == extent.bsize + */ + size_t md_order_indices[HR_MAX_EXTENTS] = { 0 }; for (size_t i = 0; i < vol->extent_no; i++) { if (assembly_svc_id_order[i] == 0) { @@ -254,6 +259,7 @@ errno_t hr_fill_vol_from_meta(hr_volume_t *vol) return rc; } +/* XXX: rewrite with read_metadata_block() */ static errno_t read_metadata(service_id_t dev, hr_metadata_t *metadata) { errno_t rc; @@ -263,10 +269,10 @@ static errno_t read_metadata(service_id_t dev, hr_metadata_t *metadata) if (rc != EOK) return rc; - if (nblocks < HR_META_SIZE + HR_META_OFF) + if (nblocks < HR_META_SIZE) return EINVAL; - rc = block_read_direct(dev, HR_META_OFF, HR_META_SIZE, metadata); + rc = block_read_direct(dev, nblocks - 1, HR_META_SIZE, metadata); if (rc != EOK) return rc; @@ -292,14 +298,14 @@ errno_t hr_get_metadata_block(service_id_t dev, void **rblock) if (rc != EOK) return rc; - if (blkno < HR_META_OFF + HR_META_SIZE) + if (blkno < HR_META_SIZE) return EINVAL; block = malloc(bsize); if (block == NULL) return ENOMEM; - rc = block_read_direct(dev, HR_META_OFF, HR_META_SIZE, block); + rc = block_read_direct(dev, blkno - 1, HR_META_SIZE, block); if (rc != EOK) { free(block); return rc; diff --git a/uspace/srv/bd/hr/superblock.h b/uspace/srv/bd/hr/superblock.h index e43cd9c5b0..aef5c22d90 100644 --- a/uspace/srv/bd/hr/superblock.h +++ b/uspace/srv/bd/hr/superblock.h @@ -38,9 +38,11 @@ #include "var.h" +/* + * Metadata is stored on the last block of an extent. + */ #define HR_META_SIZE 1 /* in blocks */ -#define HR_META_OFF 7 /* in blocks */ -#define HR_DATA_OFF (HR_META_OFF + HR_META_SIZE) +#define HR_DATA_OFF 0 #define HR_MAGIC_STR "HelenRAID" #define HR_MAGIC_SIZE 16 @@ -74,7 +76,7 @@ struct hr_metadata { uint32_t bsize; char devname[HR_DEVNAME_LEN]; -}; +} __attribute__((packed)); extern errno_t hr_write_meta_to_vol(hr_volume_t *); extern errno_t hr_write_meta_to_ext(hr_volume_t *, size_t); From 0277ec2ccf93663594e7eaa706998f2cd8d640a7 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 1 Apr 2025 10:51:52 +0200 Subject: [PATCH 168/324] hr: refactor metadata handling --- uspace/srv/bd/hr/hr.c | 6 +- uspace/srv/bd/hr/raid1.c | 7 +- uspace/srv/bd/hr/raid5.c | 8 +- uspace/srv/bd/hr/superblock.c | 283 +++++++++++++--------------------- uspace/srv/bd/hr/superblock.h | 11 +- uspace/srv/bd/hr/util.c | 2 +- 6 files changed, 122 insertions(+), 195 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 04cb027b53..5062d6232f 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -141,7 +141,11 @@ static void hr_create_srv(ipc_call_t *icall) if (rc != EOK) goto error; - rc = hr_write_meta_to_vol(new_volume); + rc = hr_metadata_init(new_volume, new_volume->in_mem_md); + if (rc != EOK) + goto error; + + rc = hr_metadata_save(new_volume); if (rc != EOK) goto error; diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 7ff8e0f267..5f4ba8ed6f 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -539,11 +539,8 @@ static errno_t hr_raid1_rebuild(void *arg) fibril_rwlock_write_unlock(&vol->states_lock); - /* - * For now write metadata at the end, because - * we don't sync metada accross extents yet. - */ - hr_write_meta_to_ext(vol, rebuild_idx); + rc = hr_metadata_save(vol); + end: if (rc != EOK) { /* diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index f09f5d9793..86e4ac5a77 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -841,11 +841,9 @@ static errno_t hr_raid5_rebuild(void *arg) "extent number %lu\n", vol->devname, vol->svc_id, hotspare_idx); hr_update_ext_status(vol, bad, HR_EXT_ONLINE); - /* - * For now write metadata at the end, because - * we don't sync metada accross extents yet. - */ - hr_write_meta_to_ext(vol, bad); + + rc = hr_metadata_save(vol); + end: (void)hr_raid5_update_vol_status(vol); diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index 600893fcef..7bf6942c98 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -49,239 +49,125 @@ #include "util.h" #include "var.h" -static errno_t read_metadata(service_id_t, hr_metadata_t *); -static errno_t hr_fill_meta_from_vol(hr_volume_t *, hr_metadata_t *); - -errno_t hr_write_meta_to_vol(hr_volume_t *vol) +errno_t hr_metadata_init(hr_volume_t *vol, hr_metadata_t *md) { HR_DEBUG("%s()", __func__); - errno_t rc; - size_t i; - hr_metadata_t *metadata; - uuid_t uuid; + str_cpy(md->magic, HR_MAGIC_SIZE, HR_MAGIC_STR); - metadata = calloc(1, HR_META_SIZE * vol->bsize); - if (metadata == NULL) - return ENOMEM; + md->version = HR_METADATA_VERSION; + vol->metadata_version = md->version; - rc = hr_fill_meta_from_vol(vol, metadata); - if (rc != EOK) - goto error; + md->counter = 0; + vol->counter = md->counter; + uuid_t uuid; /* rndgen */ fibril_usleep(1000); - rc = uuid_generate(&uuid); + errno_t rc = uuid_generate(&uuid); if (rc != EOK) - goto error; + return rc; /* XXX: for now we just copy byte by byte as "encoding" */ - memcpy(metadata->uuid, &uuid, HR_UUID_LEN); + memcpy(md->uuid, &uuid, HR_UUID_LEN); /* uuid_encode(&uuid, metadata->uuid); */ - for (i = 0; i < vol->extent_no; i++) { - metadata->index = host2uint32_t_le(i); + md->nblocks = vol->nblocks; + md->data_blkno = vol->data_blkno; + md->truncated_blkno = vol->truncated_blkno; + md->data_offset = vol->data_offset; + md->extent_no = vol->extent_no; + md->level = vol->level; + md->layout = vol->layout; + md->strip_size = vol->strip_size; + md->bsize = vol->bsize; + memcpy(md->devname, vol->devname, HR_DEVNAME_LEN); - rc = block_write_direct(vol->extents[i].svc_id, - vol->extents[i].blkno - 1, HR_META_SIZE, metadata); - if (rc != EOK) - goto error; - - } - - memcpy(vol->in_mem_md, metadata, sizeof(hr_metadata_t)); -error: - free(metadata); - return rc; + return EOK; } -errno_t hr_write_meta_to_ext(hr_volume_t *vol, size_t ext) +errno_t hr_metadata_save(hr_volume_t *vol) { HR_DEBUG("%s()", __func__); - errno_t rc; - hr_metadata_t *metadata; + errno_t rc = EOK; - /* XXX: use scratchpad */ - metadata = calloc(1, HR_META_SIZE * vol->bsize); - if (metadata == NULL) + void *md_block = calloc(1, vol->bsize); + if (md_block == NULL) return ENOMEM; - rc = hr_fill_meta_from_vol(vol, metadata); - if (rc != EOK) - goto error; + for (size_t i = 0; i < vol->extent_no; i++) { + hr_extent_t *ext = &vol->extents[i]; - metadata->index = host2uint32_t_le(ext); + /* TODO: special case for REBUILD */ + if (ext->status != HR_EXT_ONLINE) + continue; - rc = block_write_direct(vol->extents[ext].svc_id, - vol->extents[ext].blkno - 1, HR_META_SIZE, metadata); - if (rc != EOK) - goto error; + vol->in_mem_md->index = i; + hr_encode_metadata_to_block(vol->in_mem_md, md_block); + rc = hr_write_metadata_block(ext->svc_id, md_block); + /* + * XXX: here maybe call vol status event or the state + * callback inside, same with read_block... + * + * also think about using FGE here... maybe a bit more + * code, but faster and gratis state callback :-) + */ + if (rc != EOK) + goto error; + } error: - free(metadata); + free(md_block); return rc; } -/* - * Fill metadata members from - * specified volume. - * - * Does not fill extent index and UUID. - */ -static errno_t hr_fill_meta_from_vol(hr_volume_t *vol, hr_metadata_t *metadata) +bool hr_valid_md_magic(hr_metadata_t *md) { HR_DEBUG("%s()", __func__); - size_t meta_blkno = HR_META_SIZE; - - if (vol->level != HR_LVL_1) - meta_blkno *= vol->extent_no; - - if (vol->nblocks < meta_blkno) { - HR_ERROR("hr_fill_meta_from_vol(): volume \"%s\" does not " - " have enough space to store metada, aborting\n", - vol->devname); - return EINVAL; - } else if (vol->nblocks == meta_blkno) { - HR_ERROR("hr_fill_meta_from_vol(): volume \"%s\" would have " - "zero data blocks after writing metadata, aborting\n", - vol->devname); - return EINVAL; - } - - /* XXX: use scratchpad */ - str_cpy(metadata->magic, HR_MAGIC_SIZE, HR_MAGIC_STR); - metadata->nblocks = host2uint64_t_le(vol->nblocks); - metadata->data_blkno = host2uint64_t_le(vol->data_blkno); - metadata->truncated_blkno = host2uint64_t_le(vol->truncated_blkno); - metadata->data_offset = host2uint64_t_le(vol->data_offset); - metadata->counter = host2uint64_t_le(~(0UL)); /* XXX: unused */ - metadata->version = host2uint32_t_le(~(0U)); /* XXX: unused */ - metadata->extent_no = host2uint32_t_le(vol->extent_no); - /* index filled separately for each extent */ - metadata->level = host2uint32_t_le(vol->level); - metadata->layout = host2uint32_t_le(vol->layout); - metadata->strip_size = host2uint32_t_le(vol->strip_size); - metadata->bsize = host2uint32_t_le(vol->bsize); - str_cpy(metadata->devname, HR_DEVNAME_LEN, vol->devname); - - return EOK; -} - -bool hr_valid_md_magic(hr_metadata_t *md) -{ if (str_lcmp(md->magic, HR_MAGIC_STR, HR_MAGIC_SIZE) != 0) return false; return true; } -errno_t hr_fill_vol_from_meta(hr_volume_t *vol) +errno_t hr_write_metadata_block(service_id_t dev, const void *block) { HR_DEBUG("%s()", __func__); errno_t rc; - hr_metadata_t *metadata; - - metadata = calloc(1, HR_META_SIZE * vol->bsize); - if (metadata == NULL) - return ENOMEM; - - service_id_t assembly_svc_id_order[HR_MAX_EXTENTS] = { 0 }; - for (size_t i = 0; i < vol->extent_no; i++) - assembly_svc_id_order[i] = vol->extents[i].svc_id; - - /* - * XXX: sanitize metadata, for example if truncated_blkno <= extent.blkno - * or bsize == extent.bsize - */ - - size_t md_order_indices[HR_MAX_EXTENTS] = { 0 }; - for (size_t i = 0; i < vol->extent_no; i++) { - if (assembly_svc_id_order[i] == 0) { - /* set invalid index */ - md_order_indices[i] = vol->extent_no; - continue; - } - rc = read_metadata(assembly_svc_id_order[i], metadata); - if (rc != EOK) - goto end; - if (!hr_valid_md_magic(metadata)) - goto end; - md_order_indices[i] = uint32_t_le2host(metadata->index); - } - - for (size_t i = 0; i < vol->extent_no; i++) { - vol->extents[i].svc_id = 0; - vol->extents[i].status = HR_EXT_MISSING; - } - - /* sort */ - for (size_t i = 0; i < vol->extent_no; i++) { - for (size_t j = 0; j < vol->extent_no; j++) { - if (i == md_order_indices[j]) { - vol->extents[i].svc_id = - assembly_svc_id_order[j]; - vol->extents[i].status = HR_EXT_ONLINE; - } - } - } - - /* - * still assume metadata are in sync across extents - */ - - if (vol->extent_no != uint32_t_le2host(metadata->extent_no)) { - HR_ERROR("number of divices in array differ: specified %zu, " - "metadata states %u", - vol->extent_no, uint32_t_le2host(metadata->extent_no)); - rc = EINVAL; - goto end; - } - - /* TODO: handle version */ - vol->level = uint32_t_le2host(metadata->level); - vol->layout = (uint8_t)uint32_t_le2host(metadata->layout); - vol->strip_size = uint32_t_le2host(metadata->strip_size); - vol->nblocks = uint64_t_le2host(metadata->nblocks); - vol->data_blkno = uint64_t_le2host(metadata->data_blkno); - vol->data_offset = uint64_t_le2host(metadata->data_offset); - vol->bsize = uint32_t_le2host(metadata->bsize); - vol->counter = uint64_t_le2host(0x00); /* unused */ - - if (str_cmp(metadata->devname, vol->devname) != 0) { - HR_WARN("devname on metadata (%s) and config (%s) differ, " - "using config", metadata->devname, vol->devname); - } -end: - free(metadata); - return rc; -} - -/* XXX: rewrite with read_metadata_block() */ -static errno_t read_metadata(service_id_t dev, hr_metadata_t *metadata) -{ - errno_t rc; - uint64_t nblocks; + uint64_t blkno; + size_t bsize; - rc = block_get_nblocks(dev, &nblocks); + rc = block_get_bsize(dev, &bsize); if (rc != EOK) return rc; - if (nblocks < HR_META_SIZE) + if (bsize < sizeof(hr_metadata_t)) return EINVAL; - rc = block_read_direct(dev, nblocks - 1, HR_META_SIZE, metadata); + rc = block_get_nblocks(dev, &blkno); if (rc != EOK) return rc; - return EOK; + if (blkno < HR_META_SIZE) + return EINVAL; + + rc = block_write_direct(dev, blkno - 1, HR_META_SIZE, block); + /* + * XXX: here maybe call vol status event or the state callback... + * + * but need to pass vol pointer + */ + + return rc; } errno_t hr_get_metadata_block(service_id_t dev, void **rblock) { HR_DEBUG("%s()", __func__); + errno_t rc; uint64_t blkno; size_t bsize; @@ -306,6 +192,11 @@ errno_t hr_get_metadata_block(service_id_t dev, void **rblock) return ENOMEM; rc = block_read_direct(dev, blkno - 1, HR_META_SIZE, block); + /* + * XXX: here maybe call vol status event or the state callback... + * + * but need to pass vol pointer + */ if (rc != EOK) { free(block); return rc; @@ -320,8 +211,42 @@ errno_t hr_get_metadata_block(service_id_t dev, void **rblock) return EOK; } -void hr_decode_metadata_from_block(void *block, hr_metadata_t *metadata) +void hr_encode_metadata_to_block(hr_metadata_t *metadata, void *block) { + HR_DEBUG("%s()", __func__); + + /* + * Use scratch metadata for easier encoding without the need + * for manualy specifying offsets. + */ + hr_metadata_t scratch_md; + + memcpy(scratch_md.magic, metadata->magic, HR_MAGIC_SIZE); + memcpy(scratch_md.uuid, metadata->uuid, HR_UUID_LEN); + /* uuid_decode((uint8_t *)scratch_md.uuid, (uuid_t *)metadata->uuid); */ + + scratch_md.nblocks = host2uint64_t_le(metadata->nblocks); + scratch_md.data_blkno = host2uint64_t_le(metadata->data_blkno); + scratch_md.truncated_blkno = host2uint64_t_le( + metadata->truncated_blkno); + scratch_md.data_offset = host2uint64_t_le(metadata->data_offset); + scratch_md.counter = host2uint64_t_le(metadata->counter); + scratch_md.version = host2uint32_t_le(metadata->version); + scratch_md.extent_no = host2uint32_t_le(metadata->extent_no); + scratch_md.index = host2uint32_t_le(metadata->index); + scratch_md.level = host2uint32_t_le(metadata->level); + scratch_md.layout = host2uint32_t_le(metadata->layout); + scratch_md.strip_size = host2uint32_t_le(metadata->strip_size); + scratch_md.bsize = host2uint32_t_le(metadata->bsize); + memcpy(scratch_md.devname, metadata->devname, HR_DEVNAME_LEN); + + memcpy(block, &scratch_md, sizeof(hr_metadata_t)); +} + +void hr_decode_metadata_from_block(const void *block, hr_metadata_t *metadata) +{ + HR_DEBUG("%s()", __func__); + /* * Use scratch metadata for easier decoding without the need * for manualy specifying offsets. @@ -351,6 +276,8 @@ void hr_decode_metadata_from_block(void *block, hr_metadata_t *metadata) void hr_metadata_dump(hr_metadata_t *metadata) { + HR_DEBUG("%s()", __func__); + printf("\tmagic: %s\n", metadata->magic); printf("\tUUID: "); for (size_t i = 0; i < HR_UUID_LEN; ++i) { diff --git a/uspace/srv/bd/hr/superblock.h b/uspace/srv/bd/hr/superblock.h index aef5c22d90..2cec02c2bb 100644 --- a/uspace/srv/bd/hr/superblock.h +++ b/uspace/srv/bd/hr/superblock.h @@ -47,7 +47,7 @@ #define HR_MAGIC_STR "HelenRAID" #define HR_MAGIC_SIZE 16 #define HR_UUID_LEN 16 -/* #define HR_METADATA_VERSION 0 */ +#define HR_METADATA_VERSION 1 typedef struct hr_metadata hr_metadata_t; typedef struct hr_volume hr_volume_t; @@ -78,11 +78,12 @@ struct hr_metadata { char devname[HR_DEVNAME_LEN]; } __attribute__((packed)); -extern errno_t hr_write_meta_to_vol(hr_volume_t *); -extern errno_t hr_write_meta_to_ext(hr_volume_t *, size_t); -extern errno_t hr_fill_vol_from_meta(hr_volume_t *); +extern errno_t hr_metadata_init(hr_volume_t *, hr_metadata_t *); +extern errno_t hr_metadata_save(hr_volume_t *); +extern errno_t hr_write_metadata_block(service_id_t, const void *); extern errno_t hr_get_metadata_block(service_id_t, void **); -extern void hr_decode_metadata_from_block(void *, hr_metadata_t *); +extern void hr_encode_metadata_to_block(hr_metadata_t *, void *); +extern void hr_decode_metadata_from_block(const void *, hr_metadata_t *); extern void hr_metadata_dump(hr_metadata_t *); extern bool hr_valid_md_magic(hr_metadata_t *); diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index e04d2e032c..982648b19e 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -772,7 +772,7 @@ static errno_t hr_util_assemble_from_matching_list(list_t *list) size_t max_counter_val = 0; list_foreach(*list, link, struct svc_id_linked, iter) { - hr_metadata_dump(iter->md); + /* hr_metadata_dump(iter->md); */ if (iter->md->counter >= max_counter_val) { max_counter_val = iter->md->counter; main_md = iter->md; From 42007353e9a229e691fb2f7bc9556c5a630fca3b Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 1 Apr 2025 10:53:17 +0200 Subject: [PATCH 169/324] hr: fix printing extent states with invalid service id --- uspace/lib/device/src/hr.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index 7b4fcc968a..cac22b6688 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -227,12 +227,14 @@ static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info) printf("extents: [status] [index] [devname]\n"); for (i = 0; i < vol_info->extent_no; i++) { ext = &vol_info->extents[i]; - if (ext->status == HR_EXT_MISSING) { + if (ext->status == HR_EXT_MISSING || ext->status == HR_EXT_NONE) { devname = (char *) "MISSING-devname"; } else { rc = loc_service_get_name(ext->svc_id, &devname); - if (rc != EOK) - return rc; + if (rc != EOK) { + printf("loc_service_get_name() failed, skipping...\n"); + continue; + } } if (vol_info->level == HR_LVL_4) { if ((i == 0 && vol_info->layout == HR_RLQ_RAID4_0) || From 44da6c8309a775293c95a48a87489c5ca487c60b Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 1 Apr 2025 10:54:01 +0200 Subject: [PATCH 170/324] hr: util.c: initialize empty extents to MISSING --- uspace/srv/bd/hr/util.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 982648b19e..5f89fea4be 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -817,6 +817,11 @@ static errno_t hr_util_assemble_from_matching_list(list_t *list) vol->extents[iter->md->index].status = HR_EXT_INVALID; } + for (size_t i = 0; i < vol->extent_no; i++) { + if (vol->extents[i].status == HR_EXT_NONE) + vol->extents[i].status = HR_EXT_MISSING; + } + rc = vol->hr_ops.create(vol); if (rc != EOK) goto error; From c7e6a3ec8a06dbf3364483b35517375c1c294162 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 1 Apr 2025 11:53:51 +0200 Subject: [PATCH 171/324] hr: align struct hr_extent members --- uspace/lib/device/include/hr.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index aa842bd7de..ebec90ff2c 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -96,8 +96,9 @@ typedef struct hr_config { } hr_config_t; typedef struct hr_extent { - service_id_t svc_id; - hr_ext_status_t status; + service_id_t svc_id; + hr_ext_status_t status; + uint64_t blkno; } hr_extent_t; typedef struct hr_vol_info { From 52be5fa628319248f82eb0e335e62fbfdbbf542c Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 1 Apr 2025 12:02:37 +0200 Subject: [PATCH 172/324] hr: increment metadata counter on volume assembly For now increment the metadata counter right on assembly, but in the future it can be deferred until the first write I/O comes our way, to allow "read-only assembly" of volumes. --- uspace/srv/bd/hr/superblock.c | 5 +++++ uspace/srv/bd/hr/util.c | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index 7bf6942c98..3967ca020d 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -86,6 +86,11 @@ errno_t hr_metadata_init(hr_volume_t *vol, hr_metadata_t *md) return EOK; } +/* + * TODO: think about thread safety, if hr_metadata_save() can + * be called from multiple threads, and if, maybe will need + * md_lock... or whatever, but dont want to stall I/Os... + */ errno_t hr_metadata_save(hr_volume_t *vol) { HR_DEBUG("%s()", __func__); diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 5f89fea4be..bcccac8fdf 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -822,6 +822,24 @@ static errno_t hr_util_assemble_from_matching_list(list_t *list) vol->extents[i].status = HR_EXT_MISSING; } + /* + * TODO: something like mark md dirty or whatever, just sync the + * vol->counter with vol->in_mem_md->counter, or merge them and only + * keep the vol->in_mem_md->counter... + * + * XXX: if thats the only thing that can change in metadata + * during volume runtime, then whatever, but if more + * things will need to be synced, think of something more clever + * + * TODO: remove from here and increment it the "first" time (if nothing + * happens - no state changes, no rebuild, etc) - only after the first + * write... but for now leave it here + */ + vol->counter++; + vol->in_mem_md->counter = vol->counter; + + hr_metadata_save(vol); + rc = vol->hr_ops.create(vol); if (rc != EOK) goto error; From bbcd06e37fca2a1ed66e00ab0b418086883bf863 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 1 Apr 2025 12:20:06 +0200 Subject: [PATCH 173/324] hr: keep counter only in memory saved metadata --- uspace/srv/bd/hr/superblock.c | 1 - uspace/srv/bd/hr/util.c | 11 +++++------ uspace/srv/bd/hr/var.h | 15 +++++++++++---- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index 3967ca020d..9044740379 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -59,7 +59,6 @@ errno_t hr_metadata_init(hr_volume_t *vol, hr_metadata_t *md) vol->metadata_version = md->version; md->counter = 0; - vol->counter = md->counter; uuid_t uuid; /* rndgen */ diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index bcccac8fdf..ef2fe7eb15 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -791,7 +791,6 @@ static errno_t hr_util_assemble_from_matching_list(list_t *list) vol->data_blkno = main_md->data_blkno; vol->truncated_blkno = main_md->truncated_blkno; vol->data_offset = main_md->data_offset; - vol->counter = main_md->counter; vol->metadata_version = main_md->version; vol->extent_no = main_md->extent_no; /* vol->level = main_md->level; */ @@ -823,9 +822,10 @@ static errno_t hr_util_assemble_from_matching_list(list_t *list) } /* - * TODO: something like mark md dirty or whatever, just sync the - * vol->counter with vol->in_mem_md->counter, or merge them and only - * keep the vol->in_mem_md->counter... + * TODO: something like mark md dirty or whatever + * - probably will be handled by each md type differently, + * by specific function pointers + * - deal with this when foreign md will be handled * * XXX: if thats the only thing that can change in metadata * during volume runtime, then whatever, but if more @@ -835,8 +835,7 @@ static errno_t hr_util_assemble_from_matching_list(list_t *list) * happens - no state changes, no rebuild, etc) - only after the first * write... but for now leave it here */ - vol->counter++; - vol->in_mem_md->counter = vol->counter; + vol->in_mem_md->counter++; hr_metadata_save(vol); diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index c172349cac..b1c053656c 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -71,9 +71,17 @@ typedef struct hr_volume { fibril_mutex_t range_lock_list_lock; /* range locks list lock */ hr_fpool_t *fge; /* fibril pool */ - uint32_t metadata_version; /* XXX: yet unused */ - - hr_metadata_t *in_mem_md; /* TODO: implement */ + /* + * TODO: also print in info, doesn't have + * to be part of hr_volume_t but just the info + * that is passed to be printed + * + * Probably just defer this decition until foreign md + * will be handled. + */ + uint32_t metadata_version; + + hr_metadata_t *in_mem_md; /* invariants */ size_t extent_no; /* number of extents */ @@ -101,7 +109,6 @@ typedef struct hr_volume { /* XXX: atomic_uint_least64_t? */ _Atomic uint64_t rebuild_blk; /* rebuild position */ _Atomic int open_cnt; /* open/close() counter */ - uint64_t counter; /* TODO: metadata syncing */ hr_vol_status_t status; /* volume status */ } hr_volume_t; From ca7fa5bf714d68850bec6e4959902ff61d0ccfbe Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Wed, 2 Apr 2025 20:24:11 +0200 Subject: [PATCH 174/324] hr: use macro specifiers --- uspace/app/hrctl/hrctl.c | 4 +-- uspace/lib/device/src/hr.c | 10 +++--- uspace/srv/bd/hr/io.c | 23 +++++++++--- uspace/srv/bd/hr/raid1.c | 23 ++++++------ uspace/srv/bd/hr/raid5.c | 16 +++++---- uspace/srv/bd/hr/superblock.c | 25 ++++++------- uspace/srv/bd/hr/util.c | 67 +++++++++++++++++++---------------- 7 files changed, 96 insertions(+), 72 deletions(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index 74ae070e14..8ccafbe42a 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -288,7 +288,7 @@ int main(int argc, char **argv) printf("hrctl: auto assemble rc: %s\n", str_error(rc)); } else { - printf("hrctl: auto assembled %lu volumes\n", + printf("hrctl: auto assembled %zu volumes\n", cnt); } return rc; @@ -430,7 +430,7 @@ int main(int argc, char **argv) /* XXX: here have own error codes */ printf("hrctl: auto assemble rc: %s\n", str_error(rc)); } else { - printf("hrctl: auto assembled %lu volumes\n", + printf("hrctl: auto assembled %zu volumes\n", assembled_cnt); } diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index cac22b6688..7e79581ab3 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -194,7 +194,7 @@ static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info) printf("--- vol %zu ---\n", index); - printf("svc_id: %lu\n", vol_info->svc_id); + printf("svc_id: %" PRIun "\n", vol_info->svc_id); rc = loc_service_get_name(vol_info->svc_id, &devname); if (rc != EOK) @@ -210,15 +210,15 @@ static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info) } if (vol_info->level == HR_LVL_0 || vol_info->level == HR_LVL_4) { if (vol_info->strip_size / 1024 < 1) - printf("strip size in bytes: %u\n", + printf("strip size in bytes: %" PRIu32 "\n", vol_info->strip_size); else - printf("strip size: %uK\n", + printf("strip size: %" PRIu32 "K\n", vol_info->strip_size / 1024); } - printf("size in bytes: %luMiB\n", + printf("size in bytes: %" PRIu64 "MiB\n", vol_info->nblocks * vol_info->bsize / 1024 / 1024); - printf("size in blocks: %lu\n", vol_info->nblocks); + printf("size in blocks: %" PRIu64 "\n", vol_info->nblocks); printf("block size: %zu\n", vol_info->bsize); if (vol_info->level == HR_LVL_4) diff --git a/uspace/srv/bd/hr/io.c b/uspace/srv/bd/hr/io.c index 9909802c71..03e5d7316d 100644 --- a/uspace/srv/bd/hr/io.c +++ b/uspace/srv/bd/hr/io.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -50,8 +51,22 @@ errno_t hr_io_worker(void *arg) size_t ext_idx = io->extent; errno_t rc; - HR_DEBUG("WORKER on extent: %lu, ba: %lu, cnt: %lu\n", - io->extent, io->ba, io->cnt); + const char *debug_type_str = NULL; + switch (io->type) { + case HR_BD_SYNC: + debug_type_str = "SYNC"; + break; + case HR_BD_READ: + debug_type_str = "READ"; + break; + case HR_BD_WRITE: + debug_type_str = "WRITE"; + break; + } + + HR_DEBUG("%s WORKER (%p) on extent: %zu, ba: %" PRIu64 ", " + "cnt: %" PRIu64 "\n", + debug_type_str, io, io->extent, io->ba, io->cnt); switch (io->type) { case HR_BD_SYNC: @@ -72,6 +87,8 @@ errno_t hr_io_worker(void *arg) return EINVAL; } + HR_DEBUG("WORKER (%p) rc: %s\n", io, str_error(rc)); + /* * We don't have to invalidate extents who got ENOMEM * on READ/SYNC. But when we get ENOMEM on a WRITE, we have @@ -81,8 +98,6 @@ errno_t hr_io_worker(void *arg) if (rc != EOK && (rc != ENOMEM || io->type == HR_BD_WRITE)) io->state_callback(io->vol, io->extent, rc); - HR_DEBUG("WORKER rc: %s\n", str_error(rc)); - return rc; } diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 5f4ba8ed6f..17b4e74df1 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -521,8 +522,8 @@ static errno_t hr_raid1_rebuild(void *arg) old_percent = percent; } - HR_DEBUG("hr_raid1_rebuild(): rebuild finished on \"%s\" (%lu), " - "extent no. %lu\n", vol->devname, vol->svc_id, rebuild_idx); + HR_DEBUG("hr_raid1_rebuild(): rebuild finished on \"%s\" (%" PRIun "), " + "extent no. %zu\n", vol->devname, vol->svc_id, rebuild_idx); fibril_rwlock_write_lock(&vol->states_lock); @@ -615,8 +616,8 @@ static errno_t init_rebuild(hr_volume_t *vol, size_t *rebuild_idx) hr_extent_t *rebuild_ext = &vol->extents[bad]; - HR_DEBUG("hr_raid1_rebuild(): starting REBUILD on extent no. %lu (%lu)" - "\n", bad, rebuild_ext->svc_id); + HR_DEBUG("hr_raid1_rebuild(): starting REBUILD on extent no. %zu " + "(%" PRIun ")\n", bad, rebuild_ext->svc_id); atomic_store_explicit(&vol->rebuild_blk, 0, memory_order_relaxed); @@ -686,16 +687,16 @@ static errno_t hr_raid1_restore_blocks(hr_volume_t *vol, size_t rebuild_idx, if (i + 1 >= vol->extent_no) { if (rc != ENOMEM) { - HR_ERROR("rebuild on \"%s\" (%lu), failed due " - "to too many failed extents\n", + HR_ERROR("rebuild on \"%s\" (%" PRIun "), " + "failed due to too many failed extents\n", vol->devname, vol->svc_id); } /* for now we have to invalidate the rebuild extent */ if (rc == ENOMEM) { - HR_ERROR("rebuild on \"%s\" (%lu), failed due " - "to too many failed reads, because of not " - "enough memory\n", + HR_ERROR("rebuild on \"%s\" (%" PRIun "), " + "failed due to too many failed reads, " + "because of not enough memory\n", vol->devname, vol->svc_id); hr_raid1_ext_state_callback(vol, rebuild_idx, ENOMEM); @@ -717,8 +718,8 @@ static errno_t hr_raid1_restore_blocks(hr_volume_t *vol, size_t rebuild_idx, */ hr_raid1_ext_state_callback(vol, rebuild_idx, rc); - HR_ERROR("rebuild on \"%s\" (%lu), failed due to " - "the rebuilt extent no. %lu WRITE (rc: %s)\n", + HR_ERROR("rebuild on \"%s\" (%" PRIun "), failed due to " + "the rebuilt extent no. %zu WRITE (rc: %s)\n", vol->devname, vol->svc_id, rebuild_idx, str_error(rc)); return rc; diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 86e4ac5a77..f9b6e226be 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -769,7 +770,7 @@ static errno_t hr_raid5_rebuild(void *arg) hr_extent_t *rebuild_ext = &vol->extents[bad]; - HR_DEBUG("hr_raid5_rebuild(): starting rebuild on (%lu)\n", + HR_DEBUG("hr_raid5_rebuild(): starting rebuild on (%" PRIun ")\n", rebuild_ext->svc_id); hr_update_ext_status(vol, bad, HR_EXT_REBUILD); @@ -803,8 +804,9 @@ static errno_t hr_raid5_rebuild(void *arg) ba, cnt, buf); if (rc != EOK) { hr_raid5_handle_extent_error(vol, i, rc); - HR_ERROR("rebuild on \"%s\" (%lu), failed due " - "to a failed ONLINE extent, number %lu\n", + HR_ERROR("rebuild on \"%s\" (%" PRIun "), " + "failed due to a failed ONLINE extent, " + "number %zu\n", vol->devname, vol->svc_id, i); goto end; } @@ -818,8 +820,8 @@ static errno_t hr_raid5_rebuild(void *arg) rc = block_write_direct(rebuild_ext->svc_id, ba, cnt, xorbuf); if (rc != EOK) { hr_raid5_handle_extent_error(vol, bad, rc); - HR_ERROR("rebuild on \"%s\" (%lu), failed due to " - "the rebuilt extent number %lu failing\n", + HR_ERROR("rebuild on \"%s\" (%" PRIun "), failed due to " + "the rebuilt extent number %zu failing\n", vol->devname, vol->svc_id, bad); goto end; } @@ -837,8 +839,8 @@ static errno_t hr_raid5_rebuild(void *arg) fibril_rwlock_write_lock(&vol->states_lock); } - HR_DEBUG("hr_raid5_rebuild(): rebuild finished on \"%s\" (%lu), " - "extent number %lu\n", vol->devname, vol->svc_id, hotspare_idx); + HR_DEBUG("hr_raid5_rebuild(): rebuild finished on \"%s\" (%" PRIun "), " + "extent number %zu\n", vol->devname, vol->svc_id, hotspare_idx); hr_update_ext_status(vol, bad, HR_EXT_ONLINE); diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index 9044740379..4bd37318c9 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -290,18 +291,18 @@ void hr_metadata_dump(hr_metadata_t *metadata) printf(" "); } printf("\n"); - printf("\tnblocks: %lu\n", metadata->nblocks); - printf("\tdata_blkno: %lu\n", metadata->data_blkno); - printf("\ttruncated_blkno: %lu\n", metadata->truncated_blkno); - printf("\tdata_offset: %lu\n", metadata->data_offset); - printf("\tcounter: %lu\n", metadata->counter); - printf("\tversion: %u\n", metadata->version); - printf("\textent_no: %u\n", metadata->extent_no); - printf("\tindex: %u\n", metadata->index); - printf("\tlevel: %u\n", metadata->level); - printf("\tlayout: %u\n", metadata->layout); - printf("\tstrip_size: %u\n", metadata->strip_size); - printf("\tbsize: %u\n", metadata->bsize); + printf("\tnblocks: %" PRIu64 "\n", metadata->nblocks); + printf("\tdata_blkno: %" PRIu64 "\n", metadata->data_blkno); + printf("\ttruncated_blkno: %" PRIu64 "\n", metadata->truncated_blkno); + printf("\tdata_offset: %" PRIu64 "\n", metadata->data_offset); + printf("\tcounter: %" PRIu64 "\n", metadata->counter); + printf("\tversion: %" PRIu32 "\n", metadata->version); + printf("\textent_no: %" PRIu32 "\n", metadata->extent_no); + printf("\tindex: %" PRIu32 "\n", metadata->index); + printf("\tlevel: %" PRIu32 "\n", metadata->level); + printf("\tlayout: %" PRIu32 "\n", metadata->layout); + printf("\tstrip_size: %" PRIu32 "\n", metadata->strip_size); + printf("\tbsize: %" PRIu32 "\n", metadata->bsize); printf("\tdevname: %s\n", metadata->devname); } diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index ef2fe7eb15..1f2141630c 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -233,7 +234,8 @@ errno_t hr_init_extents_from_cfg(hr_volume_t *vol, hr_config_t *cfg) HR_DEBUG("%s()", __func__); errno_t rc; - size_t i, blkno, bsize; + uint64_t blkno; + size_t i, bsize; size_t last_bsize = 0; for (i = 0; i < cfg->dev_no; i++) { @@ -243,10 +245,11 @@ errno_t hr_init_extents_from_cfg(hr_volume_t *vol, hr_config_t *cfg) goto error; } - HR_DEBUG("%s(): block_init() on (%lu)\n", __func__, svc_id); + HR_DEBUG("%s(): block_init() on (%" PRIun ")\n", __func__, + svc_id); rc = block_init(svc_id); if (rc != EOK) { - HR_DEBUG("%s(): initing (%lu) failed, aborting\n", + HR_DEBUG("%s(): initing (%" PRIun ") failed, aborting\n", __func__, svc_id); goto error; } @@ -297,7 +300,7 @@ void hr_fini_devs(hr_volume_t *vol) for (i = 0; i < vol->extent_no; i++) { if (vol->extents[i].svc_id != 0) { - HR_DEBUG("hr_fini_devs(): block_fini() on (%lu)\n", + HR_DEBUG("hr_fini_devs(): block_fini() on (%" PRIun ")\n", vol->extents[i].svc_id); block_fini(vol->extents[i].svc_id); } @@ -305,7 +308,7 @@ void hr_fini_devs(hr_volume_t *vol) for (i = 0; i < vol->hotspare_no; i++) { if (vol->hotspares[i].svc_id != 0) { - HR_DEBUG("hr_fini_devs(): block_fini() on (%lu)\n", + HR_DEBUG("hr_fini_devs(): block_fini() on (%" PRIun ")\n", vol->hotspares[i].svc_id); block_fini(vol->hotspares[i].svc_id); } @@ -369,33 +372,34 @@ void hr_add_ba_offset(hr_volume_t *vol, uint64_t *ba) *ba = *ba + vol->data_offset; } -void hr_update_ext_status(hr_volume_t *vol, size_t extent, hr_ext_status_t s) +void hr_update_ext_status(hr_volume_t *vol, size_t ext_idx, hr_ext_status_t s) { if (vol->level != HR_LVL_0) assert(fibril_rwlock_is_locked(&vol->extents_lock)); assert(fibril_rwlock_is_write_locked(&vol->states_lock)); - assert(extent < vol->extent_no); + assert(ext_idx < vol->extent_no); - hr_ext_status_t old = vol->extents[extent].status; - HR_WARN("\"%s\": changing extent %lu state: %s -> %s\n", - vol->devname, extent, hr_get_ext_status_msg(old), + hr_ext_status_t old = vol->extents[ext_idx].status; + HR_WARN("\"%s\": changing extent %zu state: %s -> %s\n", + vol->devname, ext_idx, hr_get_ext_status_msg(old), hr_get_ext_status_msg(s)); - vol->extents[extent].status = s; + vol->extents[ext_idx].status = s; } -void hr_update_hotspare_status(hr_volume_t *vol, size_t hs, hr_ext_status_t s) +void hr_update_hotspare_status(hr_volume_t *vol, size_t hs_idx, + hr_ext_status_t s) { assert(fibril_mutex_is_locked(&vol->hotspare_lock)); - assert(hs < vol->hotspare_no); + assert(hs_idx < vol->hotspare_no); - hr_ext_status_t old = vol->hotspares[hs].status; - HR_WARN("\"%s\": changing hotspare %lu state: %s -> %s\n", - vol->devname, hs, hr_get_ext_status_msg(old), + hr_ext_status_t old = vol->hotspares[hs_idx].status; + HR_WARN("\"%s\": changing hotspare %zu state: %s -> %s\n", + vol->devname, hs_idx, hr_get_ext_status_msg(old), hr_get_ext_status_msg(s)); - vol->hotspares[hs].status = s; + vol->hotspares[hs_idx].status = s; } void hr_update_vol_status(hr_volume_t *vol, hr_vol_status_t new) @@ -407,29 +411,30 @@ void hr_update_vol_status(hr_volume_t *vol, hr_vol_status_t new) vol->status = new; } -void hr_update_ext_svc_id(hr_volume_t *vol, size_t extent, service_id_t new) +void hr_update_ext_svc_id(hr_volume_t *vol, size_t ext_idx, service_id_t new) { if (vol->level != HR_LVL_0) assert(fibril_rwlock_is_write_locked(&vol->extents_lock)); - assert(extent < vol->extent_no); + assert(ext_idx < vol->extent_no); - service_id_t old = vol->extents[extent].svc_id; - HR_WARN("\"%s\": changing extent no. %lu svc_id: (%lu) -> (%lu)\n", - vol->devname, extent, old, new); - vol->extents[extent].svc_id = new; + service_id_t old = vol->extents[ext_idx].svc_id; + HR_WARN("\"%s\": changing extent no. %zu svc_id: (%" PRIun ") -> " + "(%" PRIun ")\n", vol->devname, ext_idx, old, new); + vol->extents[ext_idx].svc_id = new; } -void hr_update_hotspare_svc_id(hr_volume_t *vol, size_t hs, service_id_t new) +void hr_update_hotspare_svc_id(hr_volume_t *vol, size_t hs_idx, + service_id_t new) { assert(fibril_mutex_is_locked(&vol->hotspare_lock)); - assert(hs < vol->hotspare_no); + assert(hs_idx < vol->hotspare_no); - service_id_t old = vol->hotspares[hs].svc_id; - HR_WARN("\"%s\": changing hotspare no. %lu svc_id: (%lu) -> (%lu)\n", - vol->devname, hs, old, new); - vol->hotspares[hs].svc_id = new; + service_id_t old = vol->hotspares[hs_idx].svc_id; + HR_WARN("\"%s\": changing hotspare no. %zu svc_id: (%" PRIun ") -> " + "(%" PRIun ")\n", vol->devname, hs_idx, old, new); + vol->hotspares[hs_idx].svc_id = new; } /* @@ -804,7 +809,7 @@ static errno_t hr_util_assemble_from_matching_list(list_t *list) list_foreach(*list, link, struct svc_id_linked, iter) { vol->extents[iter->md->index].svc_id = iter->svc_id; - size_t blkno; + uint64_t blkno; rc = block_get_nblocks(iter->svc_id, &blkno); if (rc != EOK) goto error; @@ -1048,7 +1053,7 @@ errno_t hr_util_add_hotspare(hr_volume_t *vol, service_id_t hotspare) if (rc != EOK) goto error; - size_t hs_blkno; + uint64_t hs_blkno; rc = block_get_nblocks(hotspare, &hs_blkno); if (rc != EOK) { block_fini(hotspare); From 800d18892aaa4584df1fb5587aaa20c4f2325a69 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 15 Apr 2025 08:55:25 +0200 Subject: [PATCH 175/324] hr: metadata saving on stop New bool argument for hr_metadata_save() to indicate if we want callback too (on array stop we don't, so we won't init a rebuild). --- uspace/srv/bd/hr/hr.c | 4 ++-- uspace/srv/bd/hr/io.c | 39 +++++++++++++++++++++++--------- uspace/srv/bd/hr/io.h | 2 +- uspace/srv/bd/hr/raid0.c | 15 +++++++++---- uspace/srv/bd/hr/raid1.c | 14 ++++++++++-- uspace/srv/bd/hr/raid5.c | 2 +- uspace/srv/bd/hr/superblock.c | 42 ++++++++++++++++++----------------- uspace/srv/bd/hr/superblock.h | 2 +- uspace/srv/bd/hr/util.c | 8 +++++-- uspace/srv/bd/hr/var.h | 6 +++++ 10 files changed, 91 insertions(+), 43 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 5062d6232f..2a7ed1a71e 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -145,11 +145,11 @@ static void hr_create_srv(ipc_call_t *icall) if (rc != EOK) goto error; - rc = hr_metadata_save(new_volume); + rc = new_volume->hr_ops.create(new_volume); if (rc != EOK) goto error; - rc = new_volume->hr_ops.create(new_volume); + rc = hr_metadata_save(new_volume, WITH_STATE_CALLBACK); if (rc != EOK) goto error; diff --git a/uspace/srv/bd/hr/io.c b/uspace/srv/bd/hr/io.c index 03e5d7316d..fd6cb9bdc6 100644 --- a/uspace/srv/bd/hr/io.c +++ b/uspace/srv/bd/hr/io.c @@ -44,11 +44,39 @@ #include "util.h" #include "var.h" +static errno_t exec_io_op(hr_io_t *); + errno_t hr_io_worker(void *arg) { hr_io_t *io = arg; - hr_extent_t *extents = (hr_extent_t *)&io->vol->extents; + + errno_t rc = exec_io_op(io); + + /* + * We don't have to invalidate extents who got ENOMEM + * on READ/SYNC. But when we get ENOMEM on a WRITE, we have + * to invalidate it, because there could have been + * other writes, there is no way to rollback. + */ + if (rc != EOK && (rc != ENOMEM || io->type == HR_BD_WRITE)) + io->vol->state_callback(io->vol, io->extent, rc); + + return rc; +} + +errno_t hr_io_worker_basic(void *arg) +{ + hr_io_t *io = arg; + + errno_t rc = exec_io_op(io); + + return rc; +} + +static errno_t exec_io_op(hr_io_t *io) +{ size_t ext_idx = io->extent; + hr_extent_t *extents = (hr_extent_t *)&io->vol->extents; errno_t rc; const char *debug_type_str = NULL; @@ -89,15 +117,6 @@ errno_t hr_io_worker(void *arg) HR_DEBUG("WORKER (%p) rc: %s\n", io, str_error(rc)); - /* - * We don't have to invalidate extents who got ENOMEM - * on READ/SYNC. But when we get ENOMEM on a WRITE, we have - * to invalidate it, because there could have been - * other writes, there is no way to rollback. - */ - if (rc != EOK && (rc != ENOMEM || io->type == HR_BD_WRITE)) - io->state_callback(io->vol, io->extent, rc); - return rc; } diff --git a/uspace/srv/bd/hr/io.h b/uspace/srv/bd/hr/io.h index 424e9e0066..9e8128b7f6 100644 --- a/uspace/srv/bd/hr/io.h +++ b/uspace/srv/bd/hr/io.h @@ -46,10 +46,10 @@ typedef struct hr_io { void *data_read; const void *data_write; hr_volume_t *vol; - void (*state_callback)(hr_volume_t *, size_t, errno_t); } hr_io_t; errno_t hr_io_worker(void *); +errno_t hr_io_worker_basic(void *); #endif diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index 3851a62b63..a683ec26ad 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -53,7 +53,7 @@ #include "var.h" static void hr_raid0_update_vol_status(hr_volume_t *); -static void raid0_state_callback(hr_volume_t *, size_t, errno_t); +static void hr_raid0_state_callback(hr_volume_t *, size_t, errno_t); static errno_t hr_raid0_bd_op(hr_bd_op_type_t, bd_srv_t *, aoff64_t, size_t, void *, const void *, size_t); @@ -99,6 +99,8 @@ errno_t hr_raid0_create(hr_volume_t *new_volume) new_volume->hr_bds.ops = &hr_raid0_bd_ops; new_volume->hr_bds.sarg = new_volume; + new_volume->state_callback = hr_raid0_state_callback; + return EOK; } @@ -195,6 +197,13 @@ static errno_t hr_raid0_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb) static void hr_raid0_update_vol_status(hr_volume_t *vol) { + fibril_mutex_lock(&vol->md_lock); + + /* XXX: will be wrapped in md specific fcn ptrs */ + vol->in_mem_md->counter++; + + fibril_mutex_unlock(&vol->md_lock); + fibril_rwlock_read_lock(&vol->states_lock); hr_vol_status_t old_state = vol->status; @@ -220,7 +229,7 @@ static void hr_raid0_update_vol_status(hr_volume_t *vol) } } -static void raid0_state_callback(hr_volume_t *vol, size_t extent, errno_t rc) +static void hr_raid0_state_callback(hr_volume_t *vol, size_t extent, errno_t rc) { if (rc == EOK) return; @@ -271,7 +280,6 @@ static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, io->cnt = cnt; io->type = type; io->vol = vol; - io->state_callback = raid0_state_callback; hr_fgroup_submit(group, hr_io_worker, io); } @@ -325,7 +333,6 @@ static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, io->cnt = cnt; io->type = type; io->vol = vol; - io->state_callback = raid0_state_callback; hr_fgroup_submit(group, hr_io_worker, io); diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 17b4e74df1..0197b989f5 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -104,6 +104,8 @@ errno_t hr_raid1_create(hr_volume_t *new_volume) new_volume->hr_bds.ops = &hr_raid1_bd_ops; new_volume->hr_bds.sarg = new_volume; + new_volume->state_callback = hr_raid1_ext_state_callback; + /* force volume state update */ hr_mark_vol_state_dirty(new_volume); hr_raid1_update_vol_status(new_volume); @@ -222,6 +224,13 @@ static void hr_raid1_update_vol_status(hr_volume_t *vol) if (!atomic_compare_exchange_strong(&vol->state_dirty, &exp, false)) return; + fibril_mutex_lock(&vol->md_lock); + + /* XXX: will be wrapped in md specific fcn ptrs */ + vol->in_mem_md->counter++; + + fibril_mutex_unlock(&vol->md_lock); + fibril_rwlock_read_lock(&vol->extents_lock); fibril_rwlock_read_lock(&vol->states_lock); @@ -246,6 +255,7 @@ static void hr_raid1_update_vol_status(hr_volume_t *vol) } if (old_state != HR_VOL_REBUILD) { + /* XXX: allow REBUILD on INVALID extents */ if (vol->hotspare_no > 0) { fid_t fib = fibril_create(hr_raid1_rebuild, vol); @@ -426,7 +436,6 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, io->cnt = cnt; io->type = type; io->vol = vol; - io->state_callback = hr_raid1_ext_state_callback; hr_fgroup_submit(group, hr_io_worker, io); } @@ -540,7 +549,7 @@ static errno_t hr_raid1_rebuild(void *arg) fibril_rwlock_write_unlock(&vol->states_lock); - rc = hr_metadata_save(vol); + rc = hr_metadata_save(vol, WITH_STATE_CALLBACK); end: if (rc != EOK) { @@ -575,6 +584,7 @@ static errno_t init_rebuild(hr_volume_t *vol, size_t *rebuild_idx) fibril_rwlock_write_lock(&vol->states_lock); fibril_mutex_lock(&vol->hotspare_lock); + /* XXX: allow REBUILD on INVALID extents */ if (vol->hotspare_no == 0) { HR_WARN("hr_raid1_rebuild(): no free hotspares on \"%s\", " "aborting rebuild\n", vol->devname); diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index f9b6e226be..9d45594899 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -844,7 +844,7 @@ static errno_t hr_raid5_rebuild(void *arg) hr_update_ext_status(vol, bad, HR_EXT_ONLINE); - rc = hr_metadata_save(vol); + rc = hr_metadata_save(vol, WITH_STATE_CALLBACK); end: (void)hr_raid5_update_vol_status(vol); diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index 4bd37318c9..2d73f103d3 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -87,11 +87,11 @@ errno_t hr_metadata_init(hr_volume_t *vol, hr_metadata_t *md) } /* - * TODO: think about thread safety, if hr_metadata_save() can - * be called from multiple threads, and if, maybe will need - * md_lock... or whatever, but dont want to stall I/Os... + * XXX: finish this fcn documentation + * + * Returns ENOMEM else EOK */ -errno_t hr_metadata_save(hr_volume_t *vol) +errno_t hr_metadata_save(hr_volume_t *vol, bool with_state_callback) { HR_DEBUG("%s()", __func__); @@ -101,30 +101,37 @@ errno_t hr_metadata_save(hr_volume_t *vol) if (md_block == NULL) return ENOMEM; + fibril_rwlock_read_lock(&vol->extents_lock); + + fibril_mutex_lock(&vol->md_lock); + for (size_t i = 0; i < vol->extent_no; i++) { hr_extent_t *ext = &vol->extents[i]; + fibril_rwlock_read_lock(&vol->states_lock); + /* TODO: special case for REBUILD */ if (ext->status != HR_EXT_ONLINE) continue; + fibril_rwlock_read_unlock(&vol->states_lock); + vol->in_mem_md->index = i; hr_encode_metadata_to_block(vol->in_mem_md, md_block); rc = hr_write_metadata_block(ext->svc_id, md_block); - /* - * XXX: here maybe call vol status event or the state - * callback inside, same with read_block... - * - * also think about using FGE here... maybe a bit more - * code, but faster and gratis state callback :-) - */ - if (rc != EOK) - goto error; + if (with_state_callback && rc != EOK) + vol->state_callback(vol, i, rc); } -error: + fibril_mutex_unlock(&vol->md_lock); + + fibril_rwlock_read_unlock(&vol->extents_lock); + + if (with_state_callback) + vol->hr_ops.status_event(vol); + free(md_block); - return rc; + return EOK; } bool hr_valid_md_magic(hr_metadata_t *md) @@ -160,11 +167,6 @@ errno_t hr_write_metadata_block(service_id_t dev, const void *block) return EINVAL; rc = block_write_direct(dev, blkno - 1, HR_META_SIZE, block); - /* - * XXX: here maybe call vol status event or the state callback... - * - * but need to pass vol pointer - */ return rc; } diff --git a/uspace/srv/bd/hr/superblock.h b/uspace/srv/bd/hr/superblock.h index 2cec02c2bb..8933f2a657 100644 --- a/uspace/srv/bd/hr/superblock.h +++ b/uspace/srv/bd/hr/superblock.h @@ -79,7 +79,7 @@ struct hr_metadata { } __attribute__((packed)); extern errno_t hr_metadata_init(hr_volume_t *, hr_metadata_t *); -extern errno_t hr_metadata_save(hr_volume_t *); +extern errno_t hr_metadata_save(hr_volume_t *, bool); extern errno_t hr_write_metadata_block(service_id_t, const void *); extern errno_t hr_get_metadata_block(service_id_t, void **); extern void hr_encode_metadata_to_block(hr_metadata_t *, void *); diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 1f2141630c..128b3f11b2 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -144,6 +144,8 @@ errno_t hr_create_vol_struct(hr_volume_t **rvol, hr_level_t level, fibril_mutex_initialize(&vol->lock); /* XXX: will remove this */ + fibril_mutex_initialize(&vol->md_lock); + fibril_rwlock_initialize(&vol->extents_lock); fibril_rwlock_initialize(&vol->states_lock); @@ -218,6 +220,8 @@ errno_t hr_remove_volume(service_id_t svc_id) list_remove(&vol->lvolumes); fibril_rwlock_write_unlock(&hr_volumes_lock); + hr_metadata_save(vol, NO_STATE_CALLBACK); + hr_destroy_vol_struct(vol); rc = loc_service_unregister(hr_srv, svc_id); @@ -842,12 +846,12 @@ static errno_t hr_util_assemble_from_matching_list(list_t *list) */ vol->in_mem_md->counter++; - hr_metadata_save(vol); - rc = vol->hr_ops.create(vol); if (rc != EOK) goto error; + hr_metadata_save(vol, WITH_STATE_CALLBACK); + fibril_rwlock_write_lock(&hr_volumes_lock); list_foreach(hr_volumes, lvolumes, hr_volume_t, other) { diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index b1c053656c..9670899d58 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -82,6 +82,7 @@ typedef struct hr_volume { uint32_t metadata_version; hr_metadata_t *in_mem_md; + fibril_mutex_t md_lock; /* lock protecting in_mem_md */ /* invariants */ size_t extent_no; /* number of extents */ @@ -110,6 +111,7 @@ typedef struct hr_volume { _Atomic uint64_t rebuild_blk; /* rebuild position */ _Atomic int open_cnt; /* open/close() counter */ hr_vol_status_t status; /* volume status */ + void (*state_callback)(hr_volume_t *, size_t, errno_t); } hr_volume_t; typedef enum { @@ -118,6 +120,10 @@ typedef enum { HR_BD_WRITE } hr_bd_op_type_t; +/* macros for hr_metadata_save() */ +#define WITH_STATE_CALLBACK true +#define NO_STATE_CALLBACK false + typedef struct hr_range_lock { link_t link; fibril_mutex_t lock; From e77c3ed37fb77d1f1de703d621cd879ee04f6b3a Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 18 Apr 2025 20:25:31 +0200 Subject: [PATCH 176/324] hr: superblock.c,h: const quals for args --- uspace/srv/bd/hr/superblock.c | 6 +++--- uspace/srv/bd/hr/superblock.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index 2d73f103d3..69188d0208 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -134,7 +134,7 @@ errno_t hr_metadata_save(hr_volume_t *vol, bool with_state_callback) return EOK; } -bool hr_valid_md_magic(hr_metadata_t *md) +bool hr_valid_md_magic(const hr_metadata_t *md) { HR_DEBUG("%s()", __func__); @@ -218,7 +218,7 @@ errno_t hr_get_metadata_block(service_id_t dev, void **rblock) return EOK; } -void hr_encode_metadata_to_block(hr_metadata_t *metadata, void *block) +void hr_encode_metadata_to_block(const hr_metadata_t *metadata, void *block) { HR_DEBUG("%s()", __func__); @@ -281,7 +281,7 @@ void hr_decode_metadata_from_block(const void *block, hr_metadata_t *metadata) memcpy(metadata->devname, scratch_md.devname, HR_DEVNAME_LEN); } -void hr_metadata_dump(hr_metadata_t *metadata) +void hr_metadata_dump(const hr_metadata_t *metadata) { HR_DEBUG("%s()", __func__); diff --git a/uspace/srv/bd/hr/superblock.h b/uspace/srv/bd/hr/superblock.h index 8933f2a657..bbafa0171f 100644 --- a/uspace/srv/bd/hr/superblock.h +++ b/uspace/srv/bd/hr/superblock.h @@ -82,10 +82,10 @@ extern errno_t hr_metadata_init(hr_volume_t *, hr_metadata_t *); extern errno_t hr_metadata_save(hr_volume_t *, bool); extern errno_t hr_write_metadata_block(service_id_t, const void *); extern errno_t hr_get_metadata_block(service_id_t, void **); -extern void hr_encode_metadata_to_block(hr_metadata_t *, void *); +extern void hr_encode_metadata_to_block(const hr_metadata_t *, void *); extern void hr_decode_metadata_from_block(const void *, hr_metadata_t *); -extern void hr_metadata_dump(hr_metadata_t *); -extern bool hr_valid_md_magic(hr_metadata_t *); +extern void hr_metadata_dump(const hr_metadata_t *); +extern bool hr_valid_md_magic(const hr_metadata_t *); #endif From 506034057bb4777c8c01885722953431aa519ae8 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 20 Apr 2025 11:56:29 +0200 Subject: [PATCH 177/324] hr: metadata format agnostic superblock ops Put metadata specific code behind a new hr_superblock_ops_t interface, that allows to easily add support for new metadata formats. --- uspace/srv/bd/hr/hr.c | 25 +- uspace/srv/bd/hr/meson.build | 1 + uspace/srv/bd/hr/metadata/native.c | 483 +++++++++++++++++++++++++++++ uspace/srv/bd/hr/metadata/native.h | 81 +++++ uspace/srv/bd/hr/raid0.c | 9 +- uspace/srv/bd/hr/raid1.c | 11 +- uspace/srv/bd/hr/raid5.c | 7 +- uspace/srv/bd/hr/superblock.c | 271 +++------------- uspace/srv/bd/hr/superblock.h | 76 ++--- uspace/srv/bd/hr/util.c | 264 +++++++--------- uspace/srv/bd/hr/util.h | 12 +- uspace/srv/bd/hr/var.h | 15 +- 12 files changed, 786 insertions(+), 469 deletions(-) create mode 100644 uspace/srv/bd/hr/metadata/native.c create mode 100644 uspace/srv/bd/hr/metadata/native.h diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 2a7ed1a71e..baa2e2d14d 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -78,7 +78,7 @@ static void hr_create_srv(ipc_call_t *icall) errno_t rc; size_t i, size; hr_config_t *cfg; - hr_volume_t *new_volume; + hr_volume_t *vol; ipc_call_t call; if (!async_data_write_receive(&call, &size)) { @@ -126,50 +126,51 @@ static void hr_create_srv(ipc_call_t *icall) } } - rc = hr_create_vol_struct(&new_volume, cfg->level, cfg->devname); + rc = hr_create_vol_struct(&vol, cfg->level, cfg->devname, + HR_METADATA_NATIVE); if (rc != EOK) { free(cfg); async_answer_0(icall, rc); return; } - rc = hr_init_extents_from_cfg(new_volume, cfg); + rc = hr_init_extents_from_cfg(vol, cfg); if (rc != EOK) goto error; - new_volume->hr_ops.init(new_volume); + vol->hr_ops.init(vol); if (rc != EOK) goto error; - rc = hr_metadata_init(new_volume, new_volume->in_mem_md); + rc = vol->meta_ops->init_vol2meta(vol, vol->in_mem_md); if (rc != EOK) goto error; - rc = new_volume->hr_ops.create(new_volume); + rc = vol->hr_ops.create(vol); if (rc != EOK) goto error; - rc = hr_metadata_save(new_volume, WITH_STATE_CALLBACK); + rc = vol->meta_ops->save(vol, WITH_STATE_CALLBACK); if (rc != EOK) goto error; - rc = hr_register_volume(new_volume); + rc = hr_register_volume(vol); if (rc != EOK) goto error; fibril_rwlock_write_lock(&hr_volumes_lock); - list_append(&new_volume->lvolumes, &hr_volumes); + list_append(&vol->lvolumes, &hr_volumes); fibril_rwlock_write_unlock(&hr_volumes_lock); - HR_DEBUG("created volume \"%s\" (%" PRIun ")\n", new_volume->devname, - new_volume->svc_id); + HR_DEBUG("created volume \"%s\" (%" PRIun ")\n", vol->devname, + vol->svc_id); free(cfg); async_answer_0(icall, rc); return; error: free(cfg); - hr_destroy_vol_struct(new_volume); + hr_destroy_vol_struct(vol); async_answer_0(icall, rc); } diff --git a/uspace/srv/bd/hr/meson.build b/uspace/srv/bd/hr/meson.build index 4b3a319187..e30d28c485 100644 --- a/uspace/srv/bd/hr/meson.build +++ b/uspace/srv/bd/hr/meson.build @@ -31,6 +31,7 @@ src = files( 'fge.c', 'hr.c', 'io.c', + 'metadata/native.c', 'raid0.c', 'raid1.c', 'raid5.c', diff --git a/uspace/srv/bd/hr/metadata/native.c b/uspace/srv/bd/hr/metadata/native.c new file mode 100644 index 0000000000..2048357d6b --- /dev/null +++ b/uspace/srv/bd/hr/metadata/native.c @@ -0,0 +1,483 @@ +/* + * 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 +#include +#include +#include +#include + +#include "../util.h" +#include "../var.h" + +#include "native.h" + +static void *meta_native_alloc_struct(void); +static errno_t meta_native_init_vol2meta(const hr_volume_t *, void *); +static errno_t meta_native_init_meta2vol(const list_t *, + hr_volume_t *); +static void meta_native_encode(const void *, void *); +static void meta_native_decode(const void *, void *); +static errno_t meta_native_get_block(service_id_t, void **); +static errno_t meta_native_write_block(service_id_t, const void *); +static bool meta_native_has_valid_magic(const void *); +static bool meta_native_compare_uuids(const void *, const void *); +static void meta_native_inc_counter(void *); +static errno_t meta_native_save(hr_volume_t *, bool); +static const char *meta_native_get_devname(const void *); +static hr_level_t meta_native_get_level(const void *); +static uint64_t meta_native_get_data_offset(void); +static size_t meta_native_get_size(void); +static uint8_t meta_native_get_flags(void); +static metadata_type_t meta_native_get_type(void); +static void meta_native_dump(const void *); + +hr_superblock_ops_t metadata_native_ops = { + .alloc_struct = meta_native_alloc_struct, + .init_vol2meta = meta_native_init_vol2meta, + .init_meta2vol = meta_native_init_meta2vol, + .encode = meta_native_encode, + .decode = meta_native_decode, + .get_block = meta_native_get_block, + .write_block = meta_native_write_block, + .has_valid_magic = meta_native_has_valid_magic, + .compare_uuids = meta_native_compare_uuids, + .inc_counter = meta_native_inc_counter, + .save = meta_native_save, + .get_devname = meta_native_get_devname, + .get_level = meta_native_get_level, + .get_data_offset = meta_native_get_data_offset, + .get_size = meta_native_get_size, + .get_flags = meta_native_get_flags, + .get_type = meta_native_get_type, + .dump = meta_native_dump +}; + +static void *meta_native_alloc_struct(void) +{ + return calloc(1, sizeof(hr_metadata_t)); +} + +static errno_t meta_native_init_vol2meta(const hr_volume_t *vol, void *mdp) +{ + HR_DEBUG("%s()", __func__); + + hr_metadata_t *md = (hr_metadata_t *)mdp; + + str_cpy(md->magic, HR_NATIVE_MAGIC_SIZE, HR_NATIVE_MAGIC_STR); + + md->version = HR_NATIVE_METADATA_VERSION; + + md->counter = 0; + + uuid_t uuid; + /* rndgen */ + fibril_usleep(1000); + errno_t rc = uuid_generate(&uuid); + if (rc != EOK) + return rc; + + /* XXX: for now we just copy byte by byte as "encoding" */ + memcpy(md->uuid, &uuid, HR_NATIVE_UUID_LEN); + /* uuid_encode(&uuid, metadata->uuid); */ + + md->nblocks = vol->nblocks; + md->data_blkno = vol->data_blkno; + md->truncated_blkno = vol->truncated_blkno; + md->data_offset = vol->data_offset; + md->extent_no = vol->extent_no; + md->level = vol->level; + md->layout = vol->layout; + md->strip_size = vol->strip_size; + md->bsize = vol->bsize; + memcpy(md->devname, vol->devname, HR_DEVNAME_LEN); + + return EOK; +} + +static errno_t meta_native_init_meta2vol(const list_t *list, hr_volume_t *vol) +{ + HR_DEBUG("%s()", __func__); + + errno_t rc = EOK; + + hr_metadata_t *main_meta = NULL; + size_t max_counter_val = 0; + + list_foreach(*list, link, struct dev_list_member, iter) { + hr_metadata_t *iter_meta = (hr_metadata_t *)iter->md; + if (iter_meta->counter >= max_counter_val) { + max_counter_val = iter_meta->counter; + main_meta = iter_meta; + } + } + + assert(main_meta != NULL); + + vol->nblocks = main_meta->nblocks; + vol->data_blkno = main_meta->data_blkno; + vol->truncated_blkno = main_meta->truncated_blkno; + vol->data_offset = main_meta->data_offset; + vol->extent_no = main_meta->extent_no; + /* vol->level = main_meta->level; */ + vol->layout = main_meta->layout; + vol->strip_size = main_meta->strip_size; + vol->bsize = main_meta->bsize; + /* memcpy(vol->devname, main_meta->devname, HR_DEVNAME_LEN); */ + memcpy(vol->in_mem_md, main_meta, sizeof(hr_metadata_t)); + + list_foreach(*list, link, struct dev_list_member, iter) { + hr_metadata_t *iter_meta = (hr_metadata_t *)iter->md; + + vol->extents[iter_meta->index].svc_id = iter->svc_id; + + uint64_t blkno; + rc = block_get_nblocks(iter->svc_id, &blkno); + if (rc != EOK) + goto error; + + vol->extents[iter_meta->index].blkno = blkno; + + if (iter_meta->counter == max_counter_val) + vol->extents[iter_meta->index].status = HR_EXT_ONLINE; + else + vol->extents[iter_meta->index].status = HR_EXT_INVALID; + } + + for (size_t i = 0; i < vol->extent_no; i++) { + if (vol->extents[i].status == HR_EXT_NONE) + vol->extents[i].status = HR_EXT_MISSING; + } + +error: + return rc; +} + +static void meta_native_encode(const void *mdp, void *block) +{ + HR_DEBUG("%s()", __func__); + + const hr_metadata_t *metadata = (hr_metadata_t *)mdp; + + /* + * Use scratch metadata for easier encoding without the need + * for manualy specifying offsets. + */ + hr_metadata_t scratch_md; + + memcpy(scratch_md.magic, metadata->magic, HR_NATIVE_MAGIC_SIZE); + memcpy(scratch_md.uuid, metadata->uuid, HR_NATIVE_UUID_LEN); + /* uuid_decode((uint8_t *)scratch_md.uuid, (uuid_t *)metadata->uuid); */ + + scratch_md.nblocks = host2uint64_t_le(metadata->nblocks); + scratch_md.data_blkno = host2uint64_t_le(metadata->data_blkno); + scratch_md.truncated_blkno = host2uint64_t_le( + metadata->truncated_blkno); + scratch_md.data_offset = host2uint64_t_le(metadata->data_offset); + scratch_md.counter = host2uint64_t_le(metadata->counter); + scratch_md.version = host2uint32_t_le(metadata->version); + scratch_md.extent_no = host2uint32_t_le(metadata->extent_no); + scratch_md.index = host2uint32_t_le(metadata->index); + scratch_md.level = host2uint32_t_le(metadata->level); + scratch_md.layout = host2uint32_t_le(metadata->layout); + scratch_md.strip_size = host2uint32_t_le(metadata->strip_size); + scratch_md.bsize = host2uint32_t_le(metadata->bsize); + memcpy(scratch_md.devname, metadata->devname, HR_DEVNAME_LEN); + + memcpy(block, &scratch_md, sizeof(hr_metadata_t)); +} + +static void meta_native_decode(const void *block, void *mdp) +{ + HR_DEBUG("%s()", __func__); + + hr_metadata_t *metadata = (hr_metadata_t *)mdp; + + /* + * Use scratch metadata for easier decoding without the need + * for manualy specifying offsets. + */ + hr_metadata_t scratch_md; + memcpy(&scratch_md, block, sizeof(hr_metadata_t)); + + memcpy(metadata->magic, scratch_md.magic, HR_NATIVE_MAGIC_SIZE); + memcpy(metadata->uuid, scratch_md.uuid, HR_NATIVE_UUID_LEN); + /* uuid_decode((uint8_t *)scratch_md.uuid, (uuid_t *)metadata->uuid); */ + + metadata->nblocks = uint64_t_le2host(scratch_md.nblocks); + metadata->data_blkno = uint64_t_le2host(scratch_md.data_blkno); + metadata->truncated_blkno = uint64_t_le2host( + scratch_md.truncated_blkno); + metadata->data_offset = uint64_t_le2host(scratch_md.data_offset); + metadata->counter = uint64_t_le2host(scratch_md.counter); + metadata->version = uint32_t_le2host(scratch_md.version); + metadata->extent_no = uint32_t_le2host(scratch_md.extent_no); + metadata->index = uint32_t_le2host(scratch_md.index); + metadata->level = uint32_t_le2host(scratch_md.level); + metadata->layout = uint32_t_le2host(scratch_md.layout); + metadata->strip_size = uint32_t_le2host(scratch_md.strip_size); + metadata->bsize = uint32_t_le2host(scratch_md.bsize); + memcpy(metadata->devname, scratch_md.devname, HR_DEVNAME_LEN); +} + +static errno_t meta_native_get_block(service_id_t dev, void **rblock) +{ + HR_DEBUG("%s()", __func__); + + errno_t rc; + uint64_t blkno; + size_t bsize; + void *block; + + if (rblock == NULL) + return EINVAL; + + rc = block_get_bsize(dev, &bsize); + if (rc != EOK) + return rc; + + if (bsize < sizeof(hr_metadata_t)) + return EINVAL; + + rc = block_get_nblocks(dev, &blkno); + if (rc != EOK) + return rc; + + if (blkno < HR_NATIVE_META_SIZE) + return EINVAL; + + block = malloc(bsize); + if (block == NULL) + return ENOMEM; + + rc = block_read_direct(dev, blkno - 1, HR_NATIVE_META_SIZE, block); + /* + * XXX: here maybe call vol status event or the state callback... + * + * but need to pass vol pointer + */ + if (rc != EOK) { + free(block); + return rc; + } + + *rblock = block; + return EOK; +} + +static errno_t meta_native_write_block(service_id_t dev, const void *block) +{ + HR_DEBUG("%s()", __func__); + + errno_t rc; + uint64_t blkno; + size_t bsize; + + rc = block_get_bsize(dev, &bsize); + if (rc != EOK) + return rc; + + if (bsize < sizeof(hr_metadata_t)) + return EINVAL; + + rc = block_get_nblocks(dev, &blkno); + if (rc != EOK) + return rc; + + if (blkno < HR_NATIVE_META_SIZE) + return EINVAL; + + rc = block_write_direct(dev, blkno - 1, HR_NATIVE_META_SIZE, block); + + return rc; +} + +static bool meta_native_has_valid_magic(const void *mdp) +{ + HR_DEBUG("%s()", __func__); + + const hr_metadata_t *md = (hr_metadata_t *)mdp; + + if (str_lcmp(md->magic, HR_NATIVE_MAGIC_STR, HR_NATIVE_MAGIC_SIZE) != 0) + return false; + + return true; +} + +static bool meta_native_compare_uuids(const void *m1p, const void *m2p) +{ + const hr_metadata_t *m1 = m1p; + const hr_metadata_t *m2 = m2p; + if (memcmp(m1->uuid, m2->uuid, HR_NATIVE_UUID_LEN) == 0) + return true; + + return false; +} + +static void meta_native_inc_counter(void *m) +{ + hr_metadata_t *meta = (hr_metadata_t *)m; + + meta->counter++; +} + +/* + * XXX: finish this fcn documentation + * + * Returns ENOMEM else EOK + */ +static errno_t meta_native_save(hr_volume_t *vol, bool with_state_callback) +{ + HR_DEBUG("%s()", __func__); + + errno_t rc = EOK; + + void *md_block = calloc(1, vol->bsize); + if (md_block == NULL) + return ENOMEM; + + hr_metadata_t *md = (hr_metadata_t *)vol->in_mem_md; + + fibril_rwlock_read_lock(&vol->extents_lock); + + fibril_mutex_lock(&vol->md_lock); + + for (size_t i = 0; i < vol->extent_no; i++) { + hr_extent_t *ext = &vol->extents[i]; + + fibril_rwlock_read_lock(&vol->states_lock); + + /* TODO: special case for REBUILD */ + if (ext->status != HR_EXT_ONLINE) + continue; + + fibril_rwlock_read_unlock(&vol->states_lock); + + md->index = i; + meta_native_encode(md, md_block); + rc = meta_native_write_block(ext->svc_id, md_block); + if (with_state_callback && rc != EOK) + vol->state_callback(vol, i, rc); + } + + fibril_mutex_unlock(&vol->md_lock); + + fibril_rwlock_read_unlock(&vol->extents_lock); + + if (with_state_callback) + vol->hr_ops.status_event(vol); + + free(md_block); + return EOK; +} + + +static const char *meta_native_get_devname(const void *m) +{ + hr_metadata_t *meta = (hr_metadata_t *)m; + + return meta->devname; +} + +static hr_level_t meta_native_get_level(const void *m) +{ + hr_metadata_t *meta = (hr_metadata_t *)m; + + return meta->level; +} + +static uint64_t meta_native_get_data_offset(void) +{ + return HR_NATIVE_DATA_OFF; +} + +static size_t meta_native_get_size(void) +{ + return HR_NATIVE_META_SIZE; +} + +static uint8_t meta_native_get_flags(void) +{ + uint8_t flags = 0; + + flags |= HR_METADATA_HOTSPARE_SUPPORT; + + return flags; +} + +static metadata_type_t meta_native_get_type(void) +{ + return HR_METADATA_NATIVE; +} + +static void meta_native_dump(const void *mdp) +{ + HR_DEBUG("%s()", __func__); + + const hr_metadata_t *metadata = (hr_metadata_t *)mdp; + + printf("\tmagic: %s\n", metadata->magic); + printf("\tUUID: "); + for (size_t i = 0; i < HR_NATIVE_UUID_LEN; ++i) { + printf("%.2X", metadata->uuid[i]); + if (i + 1 < HR_NATIVE_UUID_LEN) + printf(" "); + } + printf("\n"); + printf("\tnblocks: %" PRIu64 "\n", metadata->nblocks); + printf("\tdata_blkno: %" PRIu64 "\n", metadata->data_blkno); + printf("\ttruncated_blkno: %" PRIu64 "\n", metadata->truncated_blkno); + printf("\tdata_offset: %" PRIu64 "\n", metadata->data_offset); + printf("\tcounter: %" PRIu64 "\n", metadata->counter); + printf("\tversion: %" PRIu32 "\n", metadata->version); + printf("\textent_no: %" PRIu32 "\n", metadata->extent_no); + printf("\tindex: %" PRIu32 "\n", metadata->index); + printf("\tlevel: %" PRIu32 "\n", metadata->level); + printf("\tlayout: %" PRIu32 "\n", metadata->layout); + printf("\tstrip_size: %" PRIu32 "\n", metadata->strip_size); + printf("\tbsize: %" PRIu32 "\n", metadata->bsize); + printf("\tdevname: %s\n", metadata->devname); +} + +/** @} + */ diff --git a/uspace/srv/bd/hr/metadata/native.h b/uspace/srv/bd/hr/metadata/native.h new file mode 100644 index 0000000000..746ee566ba --- /dev/null +++ b/uspace/srv/bd/hr/metadata/native.h @@ -0,0 +1,81 @@ +/* + * 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 + */ + +#ifndef _HR_METADATA_NATIVE_H +#define _HR_METADATA_NATIVE_H + +#include "../var.h" + +/* + * Metadata is stored on the last block of an extent. + */ +#define HR_NATIVE_META_SIZE 1 /* in blocks */ +#define HR_NATIVE_DATA_OFF 0 + +#define HR_NATIVE_MAGIC_STR "HelenRAID" +#define HR_NATIVE_MAGIC_SIZE 16 +#define HR_NATIVE_UUID_LEN 16 +#define HR_NATIVE_METADATA_VERSION 1 + +struct hr_metadata { + char magic[HR_NATIVE_MAGIC_SIZE]; + + uint8_t uuid[HR_NATIVE_UUID_LEN]; + + /* TODO: change to blkno */ + uint64_t nblocks; /* all blocks */ + uint64_t data_blkno; /* usable blocks */ + + uint64_t truncated_blkno; /* usable blocks */ + uint64_t data_offset; + + uint64_t counter; /* XXX: yet unused */ + uint32_t version; /* XXX: yet unused */ + uint32_t extent_no; + + uint32_t index; /* index of extent in volume */ + uint32_t level; + uint32_t layout; + uint32_t strip_size; + + uint32_t bsize; + + char devname[HR_DEVNAME_LEN]; +} __attribute__((packed)); + +#endif + +/** @} + */ diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index a683ec26ad..6cef85a63b 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -123,10 +123,11 @@ errno_t hr_raid0_init(hr_volume_t *vol) vol->truncated_blkno = truncated_blkno; vol->nblocks = total_blkno; - vol->data_offset = HR_DATA_OFF; + vol->data_offset = vol->meta_ops->get_data_offset(); vol->data_blkno = total_blkno; - vol->data_blkno -= HR_META_SIZE * vol->extent_no; /* count md blocks */ + /* count md blocks */ + vol->data_blkno -= vol->meta_ops->get_size() * vol->extent_no; vol->strip_size = HR_STRIP_SIZE; @@ -199,8 +200,8 @@ static void hr_raid0_update_vol_status(hr_volume_t *vol) { fibril_mutex_lock(&vol->md_lock); - /* XXX: will be wrapped in md specific fcn ptrs */ - vol->in_mem_md->counter++; + vol->meta_ops->inc_counter(vol->in_mem_md); + /* TODO: save right away */ fibril_mutex_unlock(&vol->md_lock); diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 0197b989f5..9ead725a8f 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -33,6 +33,7 @@ * @file */ +#include #include #include #include @@ -136,8 +137,8 @@ errno_t hr_raid1_init(hr_volume_t *vol) vol->truncated_blkno = truncated_blkno; vol->nblocks = truncated_blkno; - vol->data_offset = HR_DATA_OFF; - vol->data_blkno = truncated_blkno - HR_META_SIZE; + vol->data_offset = vol->meta_ops->get_data_offset(); + vol->data_blkno = truncated_blkno - vol->meta_ops->get_size(); vol->strip_size = 0; return EOK; @@ -226,8 +227,8 @@ static void hr_raid1_update_vol_status(hr_volume_t *vol) fibril_mutex_lock(&vol->md_lock); - /* XXX: will be wrapped in md specific fcn ptrs */ - vol->in_mem_md->counter++; + vol->meta_ops->inc_counter(vol->in_mem_md); + /* XXX: save right away */ fibril_mutex_unlock(&vol->md_lock); @@ -549,7 +550,7 @@ static errno_t hr_raid1_rebuild(void *arg) fibril_rwlock_write_unlock(&vol->states_lock); - rc = hr_metadata_save(vol, WITH_STATE_CALLBACK); + rc = vol->meta_ops->save(vol, WITH_STATE_CALLBACK); end: if (rc != EOK) { diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 9d45594899..50a68f6da5 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -138,10 +138,11 @@ errno_t hr_raid5_init(hr_volume_t *vol) vol->truncated_blkno = truncated_blkno; vol->nblocks = total_blkno; - vol->data_offset = HR_DATA_OFF; + vol->data_offset = vol->meta_ops->get_data_offset(); vol->data_blkno = total_blkno; - vol->data_blkno -= HR_META_SIZE * vol->extent_no; /* count md blocks */ + /* count md blocks */ + vol->data_blkno -= vol->meta_ops->get_size() * vol->extent_no; vol->data_blkno -= truncated_blkno; /* count parity */ vol->strip_size = HR_STRIP_SIZE; @@ -844,7 +845,7 @@ static errno_t hr_raid5_rebuild(void *arg) hr_update_ext_status(vol, bad, HR_EXT_ONLINE); - rc = hr_metadata_save(vol, WITH_STATE_CALLBACK); + rc = vol->meta_ops->save(vol, WITH_STATE_CALLBACK); end: (void)hr_raid5_update_vol_status(vol); diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index 69188d0208..089c50d345 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -44,268 +44,69 @@ #include #include #include -#include +#include "metadata/native.h" #include "superblock.h" #include "util.h" #include "var.h" -errno_t hr_metadata_init(hr_volume_t *vol, hr_metadata_t *md) -{ - HR_DEBUG("%s()", __func__); - - str_cpy(md->magic, HR_MAGIC_SIZE, HR_MAGIC_STR); - - md->version = HR_METADATA_VERSION; - vol->metadata_version = md->version; - - md->counter = 0; - - uuid_t uuid; - /* rndgen */ - fibril_usleep(1000); - errno_t rc = uuid_generate(&uuid); - if (rc != EOK) - return rc; - - /* XXX: for now we just copy byte by byte as "encoding" */ - memcpy(md->uuid, &uuid, HR_UUID_LEN); - /* uuid_encode(&uuid, metadata->uuid); */ - - md->nblocks = vol->nblocks; - md->data_blkno = vol->data_blkno; - md->truncated_blkno = vol->truncated_blkno; - md->data_offset = vol->data_offset; - md->extent_no = vol->extent_no; - md->level = vol->level; - md->layout = vol->layout; - md->strip_size = vol->strip_size; - md->bsize = vol->bsize; - memcpy(md->devname, vol->devname, HR_DEVNAME_LEN); - - return EOK; -} - -/* - * XXX: finish this fcn documentation - * - * Returns ENOMEM else EOK - */ -errno_t hr_metadata_save(hr_volume_t *vol, bool with_state_callback) -{ - HR_DEBUG("%s()", __func__); - - errno_t rc = EOK; - - void *md_block = calloc(1, vol->bsize); - if (md_block == NULL) - return ENOMEM; +extern hr_superblock_ops_t metadata_native_ops; - fibril_rwlock_read_lock(&vol->extents_lock); +static hr_superblock_ops_t *hr_superblock_ops_all[] = { + [HR_METADATA_NATIVE] = &metadata_native_ops +}; - fibril_mutex_lock(&vol->md_lock); - - for (size_t i = 0; i < vol->extent_no; i++) { - hr_extent_t *ext = &vol->extents[i]; - - fibril_rwlock_read_lock(&vol->states_lock); - - /* TODO: special case for REBUILD */ - if (ext->status != HR_EXT_ONLINE) - continue; - - fibril_rwlock_read_unlock(&vol->states_lock); - - vol->in_mem_md->index = i; - hr_encode_metadata_to_block(vol->in_mem_md, md_block); - rc = hr_write_metadata_block(ext->svc_id, md_block); - if (with_state_callback && rc != EOK) - vol->state_callback(vol, i, rc); - } - - fibril_mutex_unlock(&vol->md_lock); - - fibril_rwlock_read_unlock(&vol->extents_lock); - - if (with_state_callback) - vol->hr_ops.status_event(vol); - - free(md_block); - return EOK; -} - -bool hr_valid_md_magic(const hr_metadata_t *md) +hr_superblock_ops_t *get_type_ops(metadata_type_t type) { - HR_DEBUG("%s()", __func__); + assert(type >= HR_METADATA_NATIVE && type < HR_METADATA_LAST_DUMMY); - if (str_lcmp(md->magic, HR_MAGIC_STR, HR_MAGIC_SIZE) != 0) - return false; - - return true; + return hr_superblock_ops_all[type]; } -errno_t hr_write_metadata_block(service_id_t dev, const void *block) +errno_t find_metadata(service_id_t svc_id, void **rmetadata, + metadata_type_t *rtype) { HR_DEBUG("%s()", __func__); errno_t rc; - uint64_t blkno; - size_t bsize; - - rc = block_get_bsize(dev, &bsize); - if (rc != EOK) - return rc; + hr_superblock_ops_t *meta_ops; + void *meta_block; + void *metadata_struct; - if (bsize < sizeof(hr_metadata_t)) + if (rmetadata == NULL) return EINVAL; - - rc = block_get_nblocks(dev, &blkno); - if (rc != EOK) - return rc; - - if (blkno < HR_META_SIZE) + if (rtype == NULL) return EINVAL; - rc = block_write_direct(dev, blkno - 1, HR_META_SIZE, block); + volatile metadata_type_t type = HR_METADATA_NATIVE; + for (; type < HR_METADATA_LAST_DUMMY; type++) { + meta_ops = hr_superblock_ops_all[type]; - return rc; -} - -errno_t hr_get_metadata_block(service_id_t dev, void **rblock) -{ - HR_DEBUG("%s()", __func__); - - errno_t rc; - uint64_t blkno; - size_t bsize; - void *block; - - rc = block_get_bsize(dev, &bsize); - if (rc != EOK) - return rc; - - if (bsize < sizeof(hr_metadata_t)) - return EINVAL; + metadata_struct = meta_ops->alloc_struct(); + if (metadata_struct == NULL) + return ENOMEM; - rc = block_get_nblocks(dev, &blkno); - if (rc != EOK) - return rc; + rc = meta_ops->get_block(svc_id, &meta_block); + if (rc == ENOMEM) + return ENOMEM; + if (rc != EOK) + continue; - if (blkno < HR_META_SIZE) - return EINVAL; + meta_ops->decode(meta_block, metadata_struct); - block = malloc(bsize); - if (block == NULL) - return ENOMEM; + free(meta_block); - rc = block_read_direct(dev, blkno - 1, HR_META_SIZE, block); - /* - * XXX: here maybe call vol status event or the state callback... - * - * but need to pass vol pointer - */ - if (rc != EOK) { - free(block); - return rc; - } + if (!meta_ops->has_valid_magic(metadata_struct)) { + free(metadata_struct); + continue; + } - if (rblock == NULL) { - free(block); - return EINVAL; + *rmetadata = metadata_struct; + *rtype = type; + return EOK; } - *rblock = block; - return EOK; -} - -void hr_encode_metadata_to_block(const hr_metadata_t *metadata, void *block) -{ - HR_DEBUG("%s()", __func__); - - /* - * Use scratch metadata for easier encoding without the need - * for manualy specifying offsets. - */ - hr_metadata_t scratch_md; - - memcpy(scratch_md.magic, metadata->magic, HR_MAGIC_SIZE); - memcpy(scratch_md.uuid, metadata->uuid, HR_UUID_LEN); - /* uuid_decode((uint8_t *)scratch_md.uuid, (uuid_t *)metadata->uuid); */ - - scratch_md.nblocks = host2uint64_t_le(metadata->nblocks); - scratch_md.data_blkno = host2uint64_t_le(metadata->data_blkno); - scratch_md.truncated_blkno = host2uint64_t_le( - metadata->truncated_blkno); - scratch_md.data_offset = host2uint64_t_le(metadata->data_offset); - scratch_md.counter = host2uint64_t_le(metadata->counter); - scratch_md.version = host2uint32_t_le(metadata->version); - scratch_md.extent_no = host2uint32_t_le(metadata->extent_no); - scratch_md.index = host2uint32_t_le(metadata->index); - scratch_md.level = host2uint32_t_le(metadata->level); - scratch_md.layout = host2uint32_t_le(metadata->layout); - scratch_md.strip_size = host2uint32_t_le(metadata->strip_size); - scratch_md.bsize = host2uint32_t_le(metadata->bsize); - memcpy(scratch_md.devname, metadata->devname, HR_DEVNAME_LEN); - - memcpy(block, &scratch_md, sizeof(hr_metadata_t)); -} - -void hr_decode_metadata_from_block(const void *block, hr_metadata_t *metadata) -{ - HR_DEBUG("%s()", __func__); - - /* - * Use scratch metadata for easier decoding without the need - * for manualy specifying offsets. - */ - hr_metadata_t scratch_md; - memcpy(&scratch_md, block, sizeof(hr_metadata_t)); - - memcpy(metadata->magic, scratch_md.magic, HR_MAGIC_SIZE); - memcpy(metadata->uuid, scratch_md.uuid, HR_UUID_LEN); - /* uuid_decode((uint8_t *)scratch_md.uuid, (uuid_t *)metadata->uuid); */ - - metadata->nblocks = uint64_t_le2host(scratch_md.nblocks); - metadata->data_blkno = uint64_t_le2host(scratch_md.data_blkno); - metadata->truncated_blkno = uint64_t_le2host( - scratch_md.truncated_blkno); - metadata->data_offset = uint64_t_le2host(scratch_md.data_offset); - metadata->counter = uint64_t_le2host(scratch_md.counter); - metadata->version = uint32_t_le2host(scratch_md.version); - metadata->extent_no = uint32_t_le2host(scratch_md.extent_no); - metadata->index = uint32_t_le2host(scratch_md.index); - metadata->level = uint32_t_le2host(scratch_md.level); - metadata->layout = uint32_t_le2host(scratch_md.layout); - metadata->strip_size = uint32_t_le2host(scratch_md.strip_size); - metadata->bsize = uint32_t_le2host(scratch_md.bsize); - memcpy(metadata->devname, scratch_md.devname, HR_DEVNAME_LEN); -} - -void hr_metadata_dump(const hr_metadata_t *metadata) -{ - HR_DEBUG("%s()", __func__); - - printf("\tmagic: %s\n", metadata->magic); - printf("\tUUID: "); - for (size_t i = 0; i < HR_UUID_LEN; ++i) { - printf("%.2X", metadata->uuid[i]); - if (i + 1 < HR_UUID_LEN) - printf(" "); - } - printf("\n"); - printf("\tnblocks: %" PRIu64 "\n", metadata->nblocks); - printf("\tdata_blkno: %" PRIu64 "\n", metadata->data_blkno); - printf("\ttruncated_blkno: %" PRIu64 "\n", metadata->truncated_blkno); - printf("\tdata_offset: %" PRIu64 "\n", metadata->data_offset); - printf("\tcounter: %" PRIu64 "\n", metadata->counter); - printf("\tversion: %" PRIu32 "\n", metadata->version); - printf("\textent_no: %" PRIu32 "\n", metadata->extent_no); - printf("\tindex: %" PRIu32 "\n", metadata->index); - printf("\tlevel: %" PRIu32 "\n", metadata->level); - printf("\tlayout: %" PRIu32 "\n", metadata->layout); - printf("\tstrip_size: %" PRIu32 "\n", metadata->strip_size); - printf("\tbsize: %" PRIu32 "\n", metadata->bsize); - printf("\tdevname: %s\n", metadata->devname); + return ENOFS; } /** @} diff --git a/uspace/srv/bd/hr/superblock.h b/uspace/srv/bd/hr/superblock.h index bbafa0171f..f67d891061 100644 --- a/uspace/srv/bd/hr/superblock.h +++ b/uspace/srv/bd/hr/superblock.h @@ -38,54 +38,38 @@ #include "var.h" -/* - * Metadata is stored on the last block of an extent. - */ -#define HR_META_SIZE 1 /* in blocks */ -#define HR_DATA_OFF 0 - -#define HR_MAGIC_STR "HelenRAID" -#define HR_MAGIC_SIZE 16 -#define HR_UUID_LEN 16 -#define HR_METADATA_VERSION 1 - -typedef struct hr_metadata hr_metadata_t; typedef struct hr_volume hr_volume_t; -struct hr_metadata { - char magic[HR_MAGIC_SIZE]; - - uint8_t uuid[HR_UUID_LEN]; - - /* TODO: change to blkno */ - uint64_t nblocks; /* all blocks */ - uint64_t data_blkno; /* usable blocks */ - - uint64_t truncated_blkno; /* usable blocks */ - uint64_t data_offset; - - uint64_t counter; /* XXX: yet unused */ - uint32_t version; /* XXX: yet unused */ - uint32_t extent_no; - - uint32_t index; /* index of extent in volume */ - uint32_t level; - uint32_t layout; - uint32_t strip_size; - - uint32_t bsize; - - char devname[HR_DEVNAME_LEN]; -} __attribute__((packed)); - -extern errno_t hr_metadata_init(hr_volume_t *, hr_metadata_t *); -extern errno_t hr_metadata_save(hr_volume_t *, bool); -extern errno_t hr_write_metadata_block(service_id_t, const void *); -extern errno_t hr_get_metadata_block(service_id_t, void **); -extern void hr_encode_metadata_to_block(const hr_metadata_t *, void *); -extern void hr_decode_metadata_from_block(const void *, hr_metadata_t *); -extern void hr_metadata_dump(const hr_metadata_t *); -extern bool hr_valid_md_magic(const hr_metadata_t *); +typedef enum { + HR_METADATA_NATIVE = 0, + HR_METADATA_LAST_DUMMY = 1 +} metadata_type_t; + +#define HR_METADATA_HOTSPARE_SUPPORT 0x01 + +typedef struct hr_superblock_ops { + void *(*alloc_struct)(void); + errno_t (*init_vol2meta)(const hr_volume_t *, void *); + errno_t (*init_meta2vol)(const list_t *, hr_volume_t *); + void (*encode)(const void *, void *); + void (*decode)(const void *, void *); + errno_t (*get_block)(service_id_t, void **); + errno_t (*write_block)(service_id_t, const void *); + bool (*has_valid_magic)(const void *); + bool (*compare_uuids)(const void *, const void *); + void (*inc_counter)(void *); + errno_t (*save)(hr_volume_t *, bool); + const char *(*get_devname)(const void *); + hr_level_t (*get_level)(const void *); + uint64_t (*get_data_offset)(void); + size_t (*get_size)(void); + uint8_t (*get_flags)(void); + metadata_type_t (*get_type)(void); + void (*dump)(const void *); +} hr_superblock_ops_t; + +hr_superblock_ops_t *get_type_ops(metadata_type_t); +extern errno_t find_metadata(service_id_t, void **, metadata_type_t *); #endif diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 128b3f11b2..bffb698eb7 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -54,39 +54,29 @@ #include "util.h" #include "var.h" -struct svc_id_linked; - static bool hr_range_lock_overlap(hr_range_lock_t *, hr_range_lock_t *); static errno_t hr_add_svc_linked_to_list(list_t *, service_id_t, bool, - hr_metadata_t *); -static void free_svc_id_linked(struct svc_id_linked *); + void *); +static void free_dev_list_member(struct dev_list_member *); static void free_svc_id_list(list_t *); static errno_t hr_fill_disk_part_svcs_list(list_t *); static errno_t block_init_dev_list(list_t *); static void block_fini_dev_list(list_t *); static errno_t hr_util_get_matching_md_svcs_list(list_t *, list_t *, - service_id_t, hr_metadata_t *); -static errno_t hr_util_assemble_from_matching_list(list_t *); + service_id_t, metadata_type_t, void *); +static errno_t hr_util_assemble_from_matching_list(list_t *, metadata_type_t); static errno_t hr_fill_svcs_list_from_cfg(hr_config_t *, list_t *); -#define HR_RL_LIST_LOCK(vol) (fibril_mutex_lock(&vol->range_lock_list_lock)) +#define HR_RL_LIST_LOCK(vol) (fibril_mutex_lock(&(vol)->range_lock_list_lock)) #define HR_RL_LIST_UNLOCK(vol) \ - (fibril_mutex_unlock(&vol->range_lock_list_lock)) - -struct svc_id_linked { - link_t link; - service_id_t svc_id; - hr_metadata_t *md; - bool inited; - bool md_present; -}; + (fibril_mutex_unlock(&(vol)->range_lock_list_lock)) extern loc_srv_t *hr_srv; extern list_t hr_volumes; extern fibril_rwlock_t hr_volumes_lock; errno_t hr_create_vol_struct(hr_volume_t **rvol, hr_level_t level, - const char *devname) + const char *devname, metadata_type_t metadata_type) { errno_t rc; @@ -97,29 +87,34 @@ errno_t hr_create_vol_struct(hr_volume_t **rvol, hr_level_t level, str_cpy(vol->devname, HR_DEVNAME_LEN, devname); vol->level = level; + vol->meta_ops = get_type_ops(metadata_type); + switch (level) { - case HR_LVL_1: - vol->hr_ops.create = hr_raid1_create; - vol->hr_ops.init = hr_raid1_init; - vol->hr_ops.status_event = hr_raid1_status_event; - vol->hr_ops.add_hotspare = hr_raid1_add_hotspare; - break; case HR_LVL_0: vol->hr_ops.create = hr_raid0_create; vol->hr_ops.init = hr_raid0_init; vol->hr_ops.status_event = hr_raid0_status_event; break; + case HR_LVL_1: + vol->hr_ops.create = hr_raid1_create; + vol->hr_ops.init = hr_raid1_init; + vol->hr_ops.status_event = hr_raid1_status_event; + if (vol->meta_ops->get_flags() & HR_METADATA_HOTSPARE_SUPPORT) + vol->hr_ops.add_hotspare = hr_raid1_add_hotspare; + break; case HR_LVL_4: vol->hr_ops.create = hr_raid5_create; vol->hr_ops.init = hr_raid5_init; vol->hr_ops.status_event = hr_raid5_status_event; - vol->hr_ops.add_hotspare = hr_raid5_add_hotspare; + if (vol->meta_ops->get_flags() & HR_METADATA_HOTSPARE_SUPPORT) + vol->hr_ops.add_hotspare = hr_raid5_add_hotspare; break; case HR_LVL_5: vol->hr_ops.create = hr_raid5_create; vol->hr_ops.init = hr_raid5_init; vol->hr_ops.status_event = hr_raid5_status_event; - vol->hr_ops.add_hotspare = hr_raid5_add_hotspare; + if (vol->meta_ops->get_flags() & HR_METADATA_HOTSPARE_SUPPORT) + vol->hr_ops.add_hotspare = hr_raid5_add_hotspare; break; default: HR_DEBUG("unkown level: %d, aborting\n", vol->level); @@ -133,7 +128,7 @@ errno_t hr_create_vol_struct(hr_volume_t **rvol, hr_level_t level, goto error; } - vol->in_mem_md = calloc(1, sizeof(hr_metadata_t)); + vol->in_mem_md = vol->meta_ops->alloc_struct(); if (vol->in_mem_md == NULL) { free(vol->fge); rc = ENOMEM; @@ -220,7 +215,7 @@ errno_t hr_remove_volume(service_id_t svc_id) list_remove(&vol->lvolumes); fibril_rwlock_write_unlock(&hr_volumes_lock); - hr_metadata_save(vol, NO_STATE_CALLBACK); + vol->meta_ops->save(vol, NO_STATE_CALLBACK); hr_destroy_vol_struct(vol); @@ -583,27 +578,28 @@ void hr_mark_vol_state_dirty(hr_volume_t *vol) } static errno_t hr_add_svc_linked_to_list(list_t *list, service_id_t svc_id, - bool inited, hr_metadata_t *md) + bool inited, void *md) { + HR_DEBUG("%s()", __func__); + errno_t rc = EOK; - struct svc_id_linked *to_add; + struct dev_list_member *to_add; - to_add = malloc(sizeof(struct svc_id_linked)); + if (list == NULL) + return EINVAL; + + to_add = malloc(sizeof(struct dev_list_member)); if (to_add == NULL) { rc = ENOMEM; goto error; } + to_add->svc_id = svc_id; to_add->inited = inited; if (md != NULL) { - to_add->md = malloc(sizeof(hr_metadata_t)); - if (to_add->md == NULL) { - rc = ENOMEM; - goto error; - } + to_add->md = md; to_add->md_present = true; - memcpy(to_add->md, md, sizeof(*md)); } else { to_add->md_present = false; } @@ -614,8 +610,10 @@ static errno_t hr_add_svc_linked_to_list(list_t *list, service_id_t svc_id, return rc; } -static void free_svc_id_linked(struct svc_id_linked *p) +static void free_dev_list_member(struct dev_list_member *p) { + HR_DEBUG("%s()", __func__); + if (p->md_present) free(p->md); free(p); @@ -623,15 +621,19 @@ static void free_svc_id_linked(struct svc_id_linked *p) static void free_svc_id_list(list_t *list) { - struct svc_id_linked *dev_id; + HR_DEBUG("%s()", __func__); + + struct dev_list_member *dev_id; while (!list_empty(list)) { - dev_id = list_pop(list, struct svc_id_linked, link); - free_svc_id_linked(dev_id); + dev_id = list_pop(list, struct dev_list_member, link); + free_dev_list_member(dev_id); } } static errno_t hr_fill_disk_part_svcs_list(list_t *list) { + HR_DEBUG("%s()", __func__); + errno_t rc; size_t disk_count; service_id_t *disk_svcs = NULL; @@ -652,19 +654,22 @@ static errno_t hr_fill_disk_part_svcs_list(list_t *list) goto error; if (disk_info.ltype == lt_none) { - rc = hr_add_svc_linked_to_list(list, disk_svcs[i], false, NULL); + rc = hr_add_svc_linked_to_list(list, disk_svcs[i], + false, NULL); if (rc != EOK) goto error; } else { size_t part_count; service_id_t *part_ids = NULL; - rc = vbd_label_get_parts(vbd, disk_svcs[i], &part_ids, &part_count); + rc = vbd_label_get_parts(vbd, disk_svcs[i], &part_ids, + &part_count); if (rc != EOK) goto error; for (size_t j = 0; j < part_count; j++) { vbd_part_info_t part_info; - rc = vbd_part_get_info(vbd, part_ids[j], &part_info); + rc = vbd_part_get_info(vbd, part_ids[j], + &part_info); if (rc != EOK) { free(part_ids); goto error; @@ -696,9 +701,12 @@ static errno_t hr_fill_disk_part_svcs_list(list_t *list) static errno_t block_init_dev_list(list_t *list) { + HR_DEBUG("%s()", __func__); + list_foreach_safe(*list, cur_link, next_link) { - struct svc_id_linked *iter; - iter = list_get_instance(cur_link, struct svc_id_linked, link); + struct dev_list_member *iter; + iter = list_get_instance(cur_link, struct dev_list_member, + link); if (iter->inited) continue; @@ -709,7 +717,7 @@ static errno_t block_init_dev_list(list_t *list) /* XXX: figure out how it is with hotspares too */ if (rc == EEXIST) { list_remove(cur_link); - free_svc_id_linked(iter); + free_dev_list_member(iter); continue; } @@ -724,7 +732,9 @@ static errno_t block_init_dev_list(list_t *list) static void block_fini_dev_list(list_t *list) { - list_foreach(*list, link, struct svc_id_linked, iter) { + HR_DEBUG("%s()", __func__); + + list_foreach(*list, link, struct dev_list_member, iter) { if (iter->inited) { block_fini(iter->svc_id); iter->inited = false; @@ -732,35 +742,36 @@ static void block_fini_dev_list(list_t *list) } } -static errno_t hr_util_get_matching_md_svcs_list(list_t *rlist, list_t *devlist, - service_id_t svc_id, hr_metadata_t *md_main) +static errno_t hr_util_get_matching_md_svcs_list(list_t *rlist, list_t *list, + service_id_t svc_id, metadata_type_t type, void *metadata_struct_main) { + HR_DEBUG("%s()", __func__); + errno_t rc = EOK; - list_foreach(*devlist, link, struct svc_id_linked, iter) { + list_foreach(*list, link, struct dev_list_member, iter) { if (iter->svc_id == svc_id) continue; - void *md_block; - hr_metadata_t md; - rc = hr_get_metadata_block(iter->svc_id, &md_block); - if (rc != EOK) - goto error; - hr_decode_metadata_from_block(md_block, &md); - free(md_block); + void *metadata_struct; + metadata_type_t type; - if (!hr_valid_md_magic(&md)) + rc = find_metadata(iter->svc_id, &metadata_struct, &type); + if (rc == ENOFS) continue; + if (rc != EOK) + goto error; - if (memcmp(md_main->uuid, md.uuid, HR_UUID_LEN) != 0) - continue; + hr_superblock_ops_t *meta_ops = get_type_ops(type); - /* - * XXX: can I assume bsize and everything is fine when - * UUID matches? - */ + if (!meta_ops->compare_uuids(metadata_struct_main, + metadata_struct)) { + free(metadata_struct); + continue; + } - rc = hr_add_svc_linked_to_list(rlist, iter->svc_id, true, &md); + rc = hr_add_svc_linked_to_list(rlist, iter->svc_id, true, + metadata_struct); if (rc != EOK) goto error; } @@ -771,64 +782,28 @@ static errno_t hr_util_get_matching_md_svcs_list(list_t *rlist, list_t *devlist, return rc; } -static errno_t hr_util_assemble_from_matching_list(list_t *list) +static errno_t hr_util_assemble_from_matching_list(list_t *list, + metadata_type_t type) { HR_DEBUG("%s()", __func__); errno_t rc = EOK; - hr_metadata_t *main_md = NULL; - size_t max_counter_val = 0; + hr_superblock_ops_t *meta_ops = get_type_ops(type); - list_foreach(*list, link, struct svc_id_linked, iter) { - /* hr_metadata_dump(iter->md); */ - if (iter->md->counter >= max_counter_val) { - max_counter_val = iter->md->counter; - main_md = iter->md; - } - } + link_t *memb_l = list_first(list); + struct dev_list_member *memb = list_get_instance(memb_l, + struct dev_list_member, link); - assert(main_md != NULL); + hr_level_t level = meta_ops->get_level(memb->md); + const char *devname = meta_ops->get_devname(memb->md); hr_volume_t *vol; - rc = hr_create_vol_struct(&vol, (hr_level_t)main_md->level, - main_md->devname); + rc = hr_create_vol_struct(&vol, level, devname, type); if (rc != EOK) goto error; - vol->nblocks = main_md->nblocks; - vol->data_blkno = main_md->data_blkno; - vol->truncated_blkno = main_md->truncated_blkno; - vol->data_offset = main_md->data_offset; - vol->metadata_version = main_md->version; - vol->extent_no = main_md->extent_no; - /* vol->level = main_md->level; */ - vol->layout = main_md->layout; - vol->strip_size = main_md->strip_size; - vol->bsize = main_md->bsize; - /* memcpy(vol->devname, main_md->devname, HR_DEVNAME_LEN); */ - - memcpy(vol->in_mem_md, main_md, sizeof(hr_metadata_t)); - - list_foreach(*list, link, struct svc_id_linked, iter) { - vol->extents[iter->md->index].svc_id = iter->svc_id; - - uint64_t blkno; - rc = block_get_nblocks(iter->svc_id, &blkno); - if (rc != EOK) - goto error; - vol->extents[iter->md->index].blkno = blkno; - - if (iter->md->counter == max_counter_val) - vol->extents[iter->md->index].status = HR_EXT_ONLINE; - else - vol->extents[iter->md->index].status = HR_EXT_INVALID; - } - - for (size_t i = 0; i < vol->extent_no; i++) { - if (vol->extents[i].status == HR_EXT_NONE) - vol->extents[i].status = HR_EXT_MISSING; - } + meta_ops->init_meta2vol(list, vol); /* * TODO: something like mark md dirty or whatever @@ -844,26 +819,14 @@ static errno_t hr_util_assemble_from_matching_list(list_t *list) * happens - no state changes, no rebuild, etc) - only after the first * write... but for now leave it here */ - vol->in_mem_md->counter++; + (void)vol->meta_ops->inc_counter(vol->in_mem_md); rc = vol->hr_ops.create(vol); if (rc != EOK) goto error; - hr_metadata_save(vol, WITH_STATE_CALLBACK); - fibril_rwlock_write_lock(&hr_volumes_lock); - list_foreach(hr_volumes, lvolumes, hr_volume_t, other) { - uint8_t *our_uuid = vol->in_mem_md->uuid; - uint8_t *other_uuid = other->in_mem_md->uuid; - if (memcmp(our_uuid, other_uuid, HR_UUID_LEN) == 0) { - rc = EEXIST; - fibril_rwlock_write_unlock(&hr_volumes_lock); - goto error; - } - } - /* * XXX: register it here * ... if it fails on EEXIST try different name... like + 1 on the end @@ -883,6 +846,8 @@ static errno_t hr_util_assemble_from_matching_list(list_t *list) goto error; } + (void)vol->meta_ops->save(vol, WITH_STATE_CALLBACK); + list_append(&vol->lvolumes, &hr_volumes); fibril_rwlock_write_unlock(&hr_volumes_lock); @@ -895,9 +860,12 @@ static errno_t hr_util_assemble_from_matching_list(list_t *list) static errno_t hr_fill_svcs_list_from_cfg(hr_config_t *cfg, list_t *list) { + HR_DEBUG("%s()", __func__); + errno_t rc = EOK; for (size_t i = 0; i < cfg->dev_no; ++i) { - rc = hr_add_svc_linked_to_list(list, cfg->devs[i], false, NULL); + rc = hr_add_svc_linked_to_list(list, cfg->devs[i], false, + NULL); if (rc != EOK) goto error; } @@ -943,28 +911,23 @@ errno_t hr_util_try_assemble(hr_config_t *cfg, size_t *rassembled_cnt) if (rc != EOK) goto error; - struct svc_id_linked *iter; + struct dev_list_member *iter; while (!list_empty(&dev_id_list)) { - iter = list_pop(&dev_id_list, struct svc_id_linked, link); - - void *metadata_block; - hr_metadata_t metadata; - - rc = hr_get_metadata_block(iter->svc_id, &metadata_block); - if (rc != EOK) - goto error; + iter = list_pop(&dev_id_list, struct dev_list_member, link); - hr_decode_metadata_from_block(metadata_block, &metadata); + void *metadata_struct_main; + metadata_type_t type; - free(metadata_block); - - if (!hr_valid_md_magic(&metadata)) { + rc = find_metadata(iter->svc_id, &metadata_struct_main, &type); + if (rc == ENOFS) { block_fini(iter->svc_id); - free_svc_id_linked(iter); + free_dev_list_member(iter); + rc = EOK; continue; } - /* hr_metadata_dump(&metadata); */ + if (rc != EOK) + goto error; char *svc_name = NULL; rc = loc_service_get_name(iter->svc_id, &svc_name); @@ -980,33 +943,34 @@ errno_t hr_util_try_assemble(hr_config_t *cfg, size_t *rassembled_cnt) list_initialize(&matching_svcs_list); rc = hr_util_get_matching_md_svcs_list(&matching_svcs_list, - &dev_id_list, iter->svc_id, &metadata); + &dev_id_list, iter->svc_id, type, metadata_struct_main); if (rc != EOK) goto error; /* add current iter to list as well */ rc = hr_add_svc_linked_to_list(&matching_svcs_list, - iter->svc_id, true, &metadata); + iter->svc_id, true, metadata_struct_main); if (rc != EOK) { free_svc_id_list(&matching_svcs_list); goto error; } /* remove matching list members from dev_id_list */ - list_foreach(matching_svcs_list, link, struct svc_id_linked, + list_foreach(matching_svcs_list, link, struct dev_list_member, iter2) { - struct svc_id_linked *to_remove; + struct dev_list_member *to_remove; list_foreach_safe(dev_id_list, cur_link, next_link) { to_remove = list_get_instance(cur_link, - struct svc_id_linked, link); + struct dev_list_member, link); if (to_remove->svc_id == iter2->svc_id) { list_remove(cur_link); - free_svc_id_linked(to_remove); + free_dev_list_member(to_remove); } } } - rc = hr_util_assemble_from_matching_list(&matching_svcs_list); + rc = hr_util_assemble_from_matching_list(&matching_svcs_list, + type); switch (rc) { case EOK: asm_cnt++; @@ -1064,11 +1028,7 @@ errno_t hr_util_add_hotspare(hr_volume_t *vol, service_id_t hotspare) goto error; } - /* - * TODO: make more flexible, when will have foreign md, the calculation - * will differ, maybe something new like vol->md_hs_blkno will be enough - */ - if (hs_blkno < vol->truncated_blkno - HR_META_SIZE) { + if (hs_blkno < vol->truncated_blkno - vol->meta_ops->get_size()) { rc = EINVAL; block_fini(hotspare); goto error; diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index 5a702b2e4a..569409b1c8 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -36,12 +36,22 @@ #ifndef _HR_UTIL_H #define _HR_UTIL_H +#include #include #include #include +#include "superblock.h" #include "var.h" +struct dev_list_member { + link_t link; + service_id_t svc_id; + void *md; + bool inited; + bool md_present; +}; + #define HR_DEBUG(format, ...) \ log_msg(LOG_DEFAULT, LVL_DEBUG, format, ##__VA_ARGS__) @@ -53,7 +63,7 @@ extern errno_t hr_create_vol_struct(hr_volume_t **, hr_level_t, - const char *); + const char *, metadata_type_t); extern void hr_destroy_vol_struct(hr_volume_t *); extern hr_volume_t *hr_get_volume(service_id_t); extern errno_t hr_remove_volume(service_id_t); diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index 9670899d58..15e3f17b0e 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -52,6 +52,7 @@ struct hr_volume; typedef struct hr_volume hr_volume_t; typedef struct hr_metadata hr_metadata_t; +typedef struct hr_superblock_ops hr_superblock_ops_t; typedef struct hr_ops { errno_t (*create)(hr_volume_t *); @@ -71,19 +72,11 @@ typedef struct hr_volume { fibril_mutex_t range_lock_list_lock; /* range locks list lock */ hr_fpool_t *fge; /* fibril pool */ - /* - * TODO: also print in info, doesn't have - * to be part of hr_volume_t but just the info - * that is passed to be printed - * - * Probably just defer this decition until foreign md - * will be handled. - */ - uint32_t metadata_version; - - hr_metadata_t *in_mem_md; + void *in_mem_md; fibril_mutex_t md_lock; /* lock protecting in_mem_md */ + hr_superblock_ops_t *meta_ops; + /* invariants */ size_t extent_no; /* number of extents */ size_t bsize; /* block size */ From 1439414131ae92a64d863f5a619f78b195d145ed Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 20 Apr 2025 15:45:48 +0200 Subject: [PATCH 178/324] hr: util.c: style --- uspace/srv/bd/hr/util.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index bffb698eb7..8ead669f57 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -248,8 +248,8 @@ errno_t hr_init_extents_from_cfg(hr_volume_t *vol, hr_config_t *cfg) svc_id); rc = block_init(svc_id); if (rc != EOK) { - HR_DEBUG("%s(): initing (%" PRIun ") failed, aborting\n", - __func__, svc_id); + HR_DEBUG("%s(): initing (%" PRIun ") failed, " + "aborting\n", __func__, svc_id); goto error; } @@ -299,15 +299,16 @@ void hr_fini_devs(hr_volume_t *vol) for (i = 0; i < vol->extent_no; i++) { if (vol->extents[i].svc_id != 0) { - HR_DEBUG("hr_fini_devs(): block_fini() on (%" PRIun ")\n", - vol->extents[i].svc_id); + HR_DEBUG("hr_fini_devs(): block_fini() on " + "(%" PRIun ")\n", vol->extents[i].svc_id); block_fini(vol->extents[i].svc_id); } } for (i = 0; i < vol->hotspare_no; i++) { if (vol->hotspares[i].svc_id != 0) { - HR_DEBUG("hr_fini_devs(): block_fini() on (%" PRIun ")\n", + HR_DEBUG("hr_fini_devs(): block_fini() on " + "(%" PRIun ")\n", vol->hotspares[i].svc_id); block_fini(vol->hotspares[i].svc_id); } @@ -626,6 +627,7 @@ static void free_svc_id_list(list_t *list) struct dev_list_member *dev_id; while (!list_empty(list)) { dev_id = list_pop(list, struct dev_list_member, link); + free_dev_list_member(dev_id); } } From 58c43d463db984d9c3b62094468eaba2f9c04359 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 20 Apr 2025 15:46:15 +0200 Subject: [PATCH 179/324] hr: util.c: matching type as well --- uspace/srv/bd/hr/util.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 8ead669f57..e8a5b617bf 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -745,12 +745,15 @@ static void block_fini_dev_list(list_t *list) } static errno_t hr_util_get_matching_md_svcs_list(list_t *rlist, list_t *list, - service_id_t svc_id, metadata_type_t type, void *metadata_struct_main) + service_id_t svc_id, metadata_type_t type_main, void *metadata_struct_main) { HR_DEBUG("%s()", __func__); errno_t rc = EOK; + hr_superblock_ops_t *meta_ops = get_type_ops(type_main); + meta_ops->dump(metadata_struct_main); + list_foreach(*list, link, struct dev_list_member, iter) { if (iter->svc_id == svc_id) continue; @@ -764,7 +767,10 @@ static errno_t hr_util_get_matching_md_svcs_list(list_t *rlist, list_t *list, if (rc != EOK) goto error; - hr_superblock_ops_t *meta_ops = get_type_ops(type); + if (type != type_main) { + free(metadata_struct); + continue; + } if (!meta_ops->compare_uuids(metadata_struct_main, metadata_struct)) { From 6a854c51246232c1010764cc8a5b624467a413e8 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 20 Apr 2025 15:49:36 +0200 Subject: [PATCH 180/324] srv/hr/metadata/native.c: no explicit arg casting --- uspace/srv/bd/hr/metadata/native.c | 39 +++++++++++++++--------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/uspace/srv/bd/hr/metadata/native.c b/uspace/srv/bd/hr/metadata/native.c index 2048357d6b..ec42863d87 100644 --- a/uspace/srv/bd/hr/metadata/native.c +++ b/uspace/srv/bd/hr/metadata/native.c @@ -98,11 +98,11 @@ static void *meta_native_alloc_struct(void) return calloc(1, sizeof(hr_metadata_t)); } -static errno_t meta_native_init_vol2meta(const hr_volume_t *vol, void *mdp) +static errno_t meta_native_init_vol2meta(const hr_volume_t *vol, void *md_v) { HR_DEBUG("%s()", __func__); - hr_metadata_t *md = (hr_metadata_t *)mdp; + hr_metadata_t *md = md_v; str_cpy(md->magic, HR_NATIVE_MAGIC_SIZE, HR_NATIVE_MAGIC_STR); @@ -193,11 +193,11 @@ static errno_t meta_native_init_meta2vol(const list_t *list, hr_volume_t *vol) return rc; } -static void meta_native_encode(const void *mdp, void *block) +static void meta_native_encode(const void *md_v, void *block) { HR_DEBUG("%s()", __func__); - const hr_metadata_t *metadata = (hr_metadata_t *)mdp; + const hr_metadata_t *metadata = md_v; /* * Use scratch metadata for easier encoding without the need @@ -227,11 +227,11 @@ static void meta_native_encode(const void *mdp, void *block) memcpy(block, &scratch_md, sizeof(hr_metadata_t)); } -static void meta_native_decode(const void *block, void *mdp) +static void meta_native_decode(const void *block, void *md_v) { HR_DEBUG("%s()", __func__); - hr_metadata_t *metadata = (hr_metadata_t *)mdp; + hr_metadata_t *metadata = md_v; /* * Use scratch metadata for easier decoding without the need @@ -332,11 +332,11 @@ static errno_t meta_native_write_block(service_id_t dev, const void *block) return rc; } -static bool meta_native_has_valid_magic(const void *mdp) +static bool meta_native_has_valid_magic(const void *md_v) { HR_DEBUG("%s()", __func__); - const hr_metadata_t *md = (hr_metadata_t *)mdp; + const hr_metadata_t *md = md_v; if (str_lcmp(md->magic, HR_NATIVE_MAGIC_STR, HR_NATIVE_MAGIC_SIZE) != 0) return false; @@ -354,11 +354,11 @@ static bool meta_native_compare_uuids(const void *m1p, const void *m2p) return false; } -static void meta_native_inc_counter(void *m) +static void meta_native_inc_counter(void *md_v) { - hr_metadata_t *meta = (hr_metadata_t *)m; + hr_metadata_t *md = md_v; - meta->counter++; + md->counter++; } /* @@ -411,19 +411,18 @@ static errno_t meta_native_save(hr_volume_t *vol, bool with_state_callback) return EOK; } - -static const char *meta_native_get_devname(const void *m) +static const char *meta_native_get_devname(const void *md_v) { - hr_metadata_t *meta = (hr_metadata_t *)m; + const hr_metadata_t *md = md_v; - return meta->devname; + return md->devname; } -static hr_level_t meta_native_get_level(const void *m) +static hr_level_t meta_native_get_level(const void *md_v) { - hr_metadata_t *meta = (hr_metadata_t *)m; + const hr_metadata_t *md = md_v; - return meta->level; + return md->level; } static uint64_t meta_native_get_data_offset(void) @@ -450,11 +449,11 @@ static metadata_type_t meta_native_get_type(void) return HR_METADATA_NATIVE; } -static void meta_native_dump(const void *mdp) +static void meta_native_dump(const void *md_v) { HR_DEBUG("%s()", __func__); - const hr_metadata_t *metadata = (hr_metadata_t *)mdp; + const hr_metadata_t *metadata = md_v; printf("\tmagic: %s\n", metadata->magic); printf("\tUUID: "); From 372a9fc5c301f9fcf3648fb4d95a83c8fce078a0 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 20 Apr 2025 16:03:44 +0200 Subject: [PATCH 181/324] srv/hr/util.c: don't dump metadata --- uspace/srv/bd/hr/util.c | 1 - 1 file changed, 1 deletion(-) diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index e8a5b617bf..c6b96378b2 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -752,7 +752,6 @@ static errno_t hr_util_get_matching_md_svcs_list(list_t *rlist, list_t *list, errno_t rc = EOK; hr_superblock_ops_t *meta_ops = get_type_ops(type_main); - meta_ops->dump(metadata_struct_main); list_foreach(*list, link, struct dev_list_member, iter) { if (iter->svc_id == svc_id) From d3a23c95a79cc094b4f0ad7459cf244032dadeb9 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 20 Apr 2025 16:18:03 +0200 Subject: [PATCH 182/324] srv/hr/util.c: change log level LVL_WARN to LVL_NOTE --- uspace/srv/bd/hr/util.c | 10 +++++----- uspace/srv/bd/hr/util.h | 3 +++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index c6b96378b2..2da4e06e25 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -382,7 +382,7 @@ void hr_update_ext_status(hr_volume_t *vol, size_t ext_idx, hr_ext_status_t s) assert(ext_idx < vol->extent_no); hr_ext_status_t old = vol->extents[ext_idx].status; - HR_WARN("\"%s\": changing extent %zu state: %s -> %s\n", + HR_NOTE("\"%s\": changing extent %zu state: %s -> %s\n", vol->devname, ext_idx, hr_get_ext_status_msg(old), hr_get_ext_status_msg(s)); vol->extents[ext_idx].status = s; @@ -396,7 +396,7 @@ void hr_update_hotspare_status(hr_volume_t *vol, size_t hs_idx, assert(hs_idx < vol->hotspare_no); hr_ext_status_t old = vol->hotspares[hs_idx].status; - HR_WARN("\"%s\": changing hotspare %zu state: %s -> %s\n", + HR_NOTE("\"%s\": changing hotspare %zu state: %s -> %s\n", vol->devname, hs_idx, hr_get_ext_status_msg(old), hr_get_ext_status_msg(s)); vol->hotspares[hs_idx].status = s; @@ -406,7 +406,7 @@ void hr_update_vol_status(hr_volume_t *vol, hr_vol_status_t new) { assert(fibril_rwlock_is_write_locked(&vol->states_lock)); - HR_WARN("\"%s\": changing volume state: %s -> %s\n", vol->devname, + HR_NOTE("\"%s\": changing volume state: %s -> %s\n", vol->devname, hr_get_vol_status_msg(vol->status), hr_get_vol_status_msg(new)); vol->status = new; } @@ -419,7 +419,7 @@ void hr_update_ext_svc_id(hr_volume_t *vol, size_t ext_idx, service_id_t new) assert(ext_idx < vol->extent_no); service_id_t old = vol->extents[ext_idx].svc_id; - HR_WARN("\"%s\": changing extent no. %zu svc_id: (%" PRIun ") -> " + HR_NOTE("\"%s\": changing extent no. %zu svc_id: (%" PRIun ") -> " "(%" PRIun ")\n", vol->devname, ext_idx, old, new); vol->extents[ext_idx].svc_id = new; } @@ -432,7 +432,7 @@ void hr_update_hotspare_svc_id(hr_volume_t *vol, size_t hs_idx, assert(hs_idx < vol->hotspare_no); service_id_t old = vol->hotspares[hs_idx].svc_id; - HR_WARN("\"%s\": changing hotspare no. %zu svc_id: (%" PRIun ") -> " + HR_NOTE("\"%s\": changing hotspare no. %zu svc_id: (%" PRIun ") -> " "(%" PRIun ")\n", vol->devname, hs_idx, old, new); vol->hotspares[hs_idx].svc_id = new; } diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index 569409b1c8..7f6412e7b7 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -55,6 +55,9 @@ struct dev_list_member { #define HR_DEBUG(format, ...) \ log_msg(LOG_DEFAULT, LVL_DEBUG, format, ##__VA_ARGS__) +#define HR_NOTE(format, ...) \ + log_msg(LOG_DEFAULT, LVL_NOTE, format, ##__VA_ARGS__) + #define HR_WARN(format, ...) \ log_msg(LOG_DEFAULT, LVL_WARN, format, ##__VA_ARGS__) From f647b8778cd26c140edea49431805075e1653b6c Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 20 Apr 2025 16:32:32 +0200 Subject: [PATCH 183/324] srv/bd/hr: remove unused nblocks variable --- uspace/srv/bd/hr/hr.c | 1 + uspace/srv/bd/hr/metadata/native.c | 5 ----- uspace/srv/bd/hr/metadata/native.h | 8 +++----- uspace/srv/bd/hr/raid0.c | 1 - uspace/srv/bd/hr/raid1.c | 1 - uspace/srv/bd/hr/raid5.c | 1 - uspace/srv/bd/hr/var.h | 1 - 7 files changed, 4 insertions(+), 14 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index baa2e2d14d..81a6a53dc4 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -376,6 +376,7 @@ static void hr_print_status_srv(ipc_call_t *icall) info.hotspare_no = vol->hotspare_no; info.level = vol->level; /* print usable number of blocks */ + /* TODO: change to data_blkno */ info.nblocks = vol->data_blkno; info.strip_size = vol->strip_size; info.bsize = vol->bsize; diff --git a/uspace/srv/bd/hr/metadata/native.c b/uspace/srv/bd/hr/metadata/native.c index ec42863d87..2fdf2f4f57 100644 --- a/uspace/srv/bd/hr/metadata/native.c +++ b/uspace/srv/bd/hr/metadata/native.c @@ -121,7 +121,6 @@ static errno_t meta_native_init_vol2meta(const hr_volume_t *vol, void *md_v) memcpy(md->uuid, &uuid, HR_NATIVE_UUID_LEN); /* uuid_encode(&uuid, metadata->uuid); */ - md->nblocks = vol->nblocks; md->data_blkno = vol->data_blkno; md->truncated_blkno = vol->truncated_blkno; md->data_offset = vol->data_offset; @@ -154,7 +153,6 @@ static errno_t meta_native_init_meta2vol(const list_t *list, hr_volume_t *vol) assert(main_meta != NULL); - vol->nblocks = main_meta->nblocks; vol->data_blkno = main_meta->data_blkno; vol->truncated_blkno = main_meta->truncated_blkno; vol->data_offset = main_meta->data_offset; @@ -209,7 +207,6 @@ static void meta_native_encode(const void *md_v, void *block) memcpy(scratch_md.uuid, metadata->uuid, HR_NATIVE_UUID_LEN); /* uuid_decode((uint8_t *)scratch_md.uuid, (uuid_t *)metadata->uuid); */ - scratch_md.nblocks = host2uint64_t_le(metadata->nblocks); scratch_md.data_blkno = host2uint64_t_le(metadata->data_blkno); scratch_md.truncated_blkno = host2uint64_t_le( metadata->truncated_blkno); @@ -244,7 +241,6 @@ static void meta_native_decode(const void *block, void *md_v) memcpy(metadata->uuid, scratch_md.uuid, HR_NATIVE_UUID_LEN); /* uuid_decode((uint8_t *)scratch_md.uuid, (uuid_t *)metadata->uuid); */ - metadata->nblocks = uint64_t_le2host(scratch_md.nblocks); metadata->data_blkno = uint64_t_le2host(scratch_md.data_blkno); metadata->truncated_blkno = uint64_t_le2host( scratch_md.truncated_blkno); @@ -463,7 +459,6 @@ static void meta_native_dump(const void *md_v) printf(" "); } printf("\n"); - printf("\tnblocks: %" PRIu64 "\n", metadata->nblocks); printf("\tdata_blkno: %" PRIu64 "\n", metadata->data_blkno); printf("\ttruncated_blkno: %" PRIu64 "\n", metadata->truncated_blkno); printf("\tdata_offset: %" PRIu64 "\n", metadata->data_offset); diff --git a/uspace/srv/bd/hr/metadata/native.h b/uspace/srv/bd/hr/metadata/native.h index 746ee566ba..44c77dcfa8 100644 --- a/uspace/srv/bd/hr/metadata/native.h +++ b/uspace/srv/bd/hr/metadata/native.h @@ -54,19 +54,17 @@ struct hr_metadata { uint8_t uuid[HR_NATIVE_UUID_LEN]; - /* TODO: change to blkno */ - uint64_t nblocks; /* all blocks */ uint64_t data_blkno; /* usable blocks */ + uint64_t truncated_blkno; /* size of smallest extent */ - uint64_t truncated_blkno; /* usable blocks */ uint64_t data_offset; + uint64_t counter; - uint64_t counter; /* XXX: yet unused */ uint32_t version; /* XXX: yet unused */ uint32_t extent_no; - uint32_t index; /* index of extent in volume */ uint32_t level; + uint32_t layout; uint32_t strip_size; diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index 6cef85a63b..46ea5036b7 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -122,7 +122,6 @@ errno_t hr_raid0_init(hr_volume_t *vol) uint64_t total_blkno = truncated_blkno * vol->extent_no; vol->truncated_blkno = truncated_blkno; - vol->nblocks = total_blkno; vol->data_offset = vol->meta_ops->get_data_offset(); vol->data_blkno = total_blkno; diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 9ead725a8f..faba34a428 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -136,7 +136,6 @@ errno_t hr_raid1_init(hr_volume_t *vol) } vol->truncated_blkno = truncated_blkno; - vol->nblocks = truncated_blkno; vol->data_offset = vol->meta_ops->get_data_offset(); vol->data_blkno = truncated_blkno - vol->meta_ops->get_size(); vol->strip_size = 0; diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 50a68f6da5..be6ad1099f 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -137,7 +137,6 @@ errno_t hr_raid5_init(hr_volume_t *vol) uint64_t total_blkno = truncated_blkno * vol->extent_no; vol->truncated_blkno = truncated_blkno; - vol->nblocks = total_blkno; vol->data_offset = vol->meta_ops->get_data_offset(); vol->data_blkno = total_blkno; diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index 15e3f17b0e..22bfca7226 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -80,7 +80,6 @@ typedef struct hr_volume { /* invariants */ size_t extent_no; /* number of extents */ size_t bsize; /* block size */ - uint64_t nblocks; /* no. of all usable blocks */ uint64_t truncated_blkno; /* blkno per extent */ uint64_t data_blkno; /* no. of user usable blocks */ uint64_t data_offset; /* user data offset in blocks */ From afec52b44d799f580739b6b31a98550db3132364 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 20 Apr 2025 16:34:22 +0200 Subject: [PATCH 184/324] srv/bd/hr/superblock.c: fix memory leak --- uspace/srv/bd/hr/superblock.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index 089c50d345..1df19cbc1a 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -87,10 +87,13 @@ errno_t find_metadata(service_id_t svc_id, void **rmetadata, return ENOMEM; rc = meta_ops->get_block(svc_id, &meta_block); - if (rc == ENOMEM) + if (rc == ENOMEM) { + free(metadata_struct); return ENOMEM; - if (rc != EOK) + } else if (rc != EOK) { + free(metadata_struct); continue; + } meta_ops->decode(meta_block, metadata_struct); From 10291a23afbd7d9a897acc61321fba27b594b427 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 20 Apr 2025 16:48:24 +0200 Subject: [PATCH 185/324] hr: FreeBSD GEOM::MIRROR metadata support --- uspace/srv/bd/hr/meson.build | 3 +- .../bd/hr/metadata/foreign/geom/g_mirror.h | 318 ++++++++++++++ .../srv/bd/hr/metadata/foreign/geom/mirror.c | 393 ++++++++++++++++++ uspace/srv/bd/hr/metadata/native.c | 10 +- uspace/srv/bd/hr/superblock.c | 15 +- uspace/srv/bd/hr/superblock.h | 7 +- 6 files changed, 735 insertions(+), 11 deletions(-) create mode 100644 uspace/srv/bd/hr/metadata/foreign/geom/g_mirror.h create mode 100644 uspace/srv/bd/hr/metadata/foreign/geom/mirror.c diff --git a/uspace/srv/bd/hr/meson.build b/uspace/srv/bd/hr/meson.build index e30d28c485..f59b1552c9 100644 --- a/uspace/srv/bd/hr/meson.build +++ b/uspace/srv/bd/hr/meson.build @@ -26,11 +26,12 @@ # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # -deps = [ 'block', 'device' ] +deps = [ 'block', 'crypto', 'device' ] src = files( 'fge.c', 'hr.c', 'io.c', + 'metadata/foreign/geom/mirror.c', 'metadata/native.c', 'raid0.c', 'raid1.c', diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/g_mirror.h b/uspace/srv/bd/hr/metadata/foreign/geom/g_mirror.h new file mode 100644 index 0000000000..4a198a5dc6 --- /dev/null +++ b/uspace/srv/bd/hr/metadata/foreign/geom/g_mirror.h @@ -0,0 +1,318 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2004-2006 Pawel Jakub Dawidek + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``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 AUTHORS OR CONTRIBUTORS 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 + */ + +#ifndef _HR_METADATA_FOREIGN_GEOM_MIRROR_H +#define _HR_METADATA_FOREIGN_GEOM_MIRROR_H + +/* needed HelenOS headers */ +#include +#include +#include + +/* new typedefs */ +typedef unsigned char u_char; +typedef unsigned int u_int; +#define bcopy(src, dst, len) memcpy(dst, src, len) + +/* copied here from */ +static __inline void +le32enc(void *pp, uint32_t u) +{ + uint8_t *p = (uint8_t *)pp; + + p[0] = u & 0xff; + p[1] = (u >> 8) & 0xff; + p[2] = (u >> 16) & 0xff; + p[3] = (u >> 24) & 0xff; +} + +static __inline void +le64enc(void *pp, uint64_t u) +{ + uint8_t *p = (uint8_t *)pp; + + le32enc(p, (uint32_t)(u & 0xffffffffU)); + le32enc(p + 4, (uint32_t)(u >> 32)); +} + +static __inline uint32_t +le32dec(const void *pp) +{ + uint8_t const *p = (uint8_t const *)pp; + + return (((unsigned)p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]); +} + +static __inline uint64_t +le64dec(const void *pp) +{ + uint8_t const *p = (uint8_t const *)pp; + + return (((uint64_t)le32dec(p + 4) << 32) | le32dec(p)); +} + +/* here continues the stripped down original header */ + +#define G_MIRROR_MAGIC "GEOM::MIRROR" + +#define G_MIRROR_BALANCE_NONE 0 +#define G_MIRROR_BALANCE_ROUND_ROBIN 1 +#define G_MIRROR_BALANCE_LOAD 2 +#define G_MIRROR_BALANCE_SPLIT 3 +#define G_MIRROR_BALANCE_PREFER 4 +#define G_MIRROR_BALANCE_MIN G_MIRROR_BALANCE_NONE +#define G_MIRROR_BALANCE_MAX G_MIRROR_BALANCE_PREFER + +#define G_MIRROR_DISK_FLAG_DIRTY 0x0000000000000001ULL +#define G_MIRROR_DISK_FLAG_SYNCHRONIZING 0x0000000000000002ULL +#define G_MIRROR_DISK_FLAG_FORCE_SYNC 0x0000000000000004ULL +#define G_MIRROR_DISK_FLAG_INACTIVE 0x0000000000000008ULL +#define G_MIRROR_DISK_FLAG_HARDCODED 0x0000000000000010ULL +#define G_MIRROR_DISK_FLAG_BROKEN 0x0000000000000020ULL +#define G_MIRROR_DISK_FLAG_CANDELETE 0x0000000000000040ULL + +#define G_MIRROR_DISK_FLAG_MASK (G_MIRROR_DISK_FLAG_DIRTY | \ + G_MIRROR_DISK_FLAG_SYNCHRONIZING | \ + G_MIRROR_DISK_FLAG_FORCE_SYNC | \ + G_MIRROR_DISK_FLAG_INACTIVE | \ + G_MIRROR_DISK_FLAG_CANDELETE) + +#define G_MIRROR_DEVICE_FLAG_NOAUTOSYNC 0x0000000000000001ULL +#define G_MIRROR_DEVICE_FLAG_NOFAILSYNC 0x0000000000000002ULL + +#define G_MIRROR_DEVICE_FLAG_DESTROY 0x0100000000000000ULL +#define G_MIRROR_DEVICE_FLAG_DRAIN 0x0200000000000000ULL +#define G_MIRROR_DEVICE_FLAG_CLOSEWAIT 0x0400000000000000ULL +#define G_MIRROR_DEVICE_FLAG_TASTING 0x0800000000000000ULL +#define G_MIRROR_DEVICE_FLAG_WIPE 0x1000000000000000ULL + +struct g_mirror_metadata { + char md_magic[16]; /* Magic value. */ + uint32_t md_version; /* Version number. */ + char md_name[16]; /* Mirror name. */ + uint32_t md_mid; /* Mirror unique ID. */ + uint32_t md_did; /* Disk unique ID. */ + uint8_t md_all; /* Number of disks in mirror. */ + uint32_t md_genid; /* Generation ID. */ + uint32_t md_syncid; /* Synchronization ID. */ + uint8_t md_priority; /* Disk priority. */ + uint32_t md_slice; /* Slice size. */ + uint8_t md_balance; /* Balance type. */ + uint64_t md_mediasize; /* Size of the smallest disk in mirror. */ + uint32_t md_sectorsize; /* Sector size. */ + uint64_t md_sync_offset; /* Synchronized offset. */ + uint64_t md_mflags; /* Additional mirror flags. */ + uint64_t md_dflags; /* Additional disk flags. */ + char md_provider[16]; /* Hardcoded provider. */ + uint64_t md_provsize; /* Provider's size. */ + u_char md_hash[16]; /* MD5 hash. */ +}; + +static __inline void +mirror_metadata_encode(struct g_mirror_metadata *md, u_char *data) +{ + uint8_t md5_hash[16]; + + bcopy(md->md_magic, data, 16); + le32enc(data + 16, md->md_version); + bcopy(md->md_name, data + 20, 16); + le32enc(data + 36, md->md_mid); + le32enc(data + 40, md->md_did); + *(data + 44) = md->md_all; + le32enc(data + 45, md->md_genid); + le32enc(data + 49, md->md_syncid); + *(data + 53) = md->md_priority; + le32enc(data + 54, md->md_slice); + *(data + 58) = md->md_balance; + le64enc(data + 59, md->md_mediasize); + le32enc(data + 67, md->md_sectorsize); + le64enc(data + 71, md->md_sync_offset); + le64enc(data + 79, md->md_mflags); + le64enc(data + 87, md->md_dflags); + bcopy(md->md_provider, data + 95, 16); + le64enc(data + 111, md->md_provsize); + + errno_t rc = create_hash(data, 119, md5_hash, HASH_MD5); + assert(rc == EOK); + bcopy(md->md_hash, data + 119, 16); +} + +static __inline int +mirror_metadata_decode_v3v4(const u_char *data, struct g_mirror_metadata *md) +{ + uint8_t md5_hash[16]; + + bcopy(data + 20, md->md_name, 16); + md->md_mid = le32dec(data + 36); + md->md_did = le32dec(data + 40); + md->md_all = *(data + 44); + md->md_genid = le32dec(data + 45); + md->md_syncid = le32dec(data + 49); + md->md_priority = *(data + 53); + md->md_slice = le32dec(data + 54); + md->md_balance = *(data + 58); + md->md_mediasize = le64dec(data + 59); + md->md_sectorsize = le32dec(data + 67); + md->md_sync_offset = le64dec(data + 71); + md->md_mflags = le64dec(data + 79); + md->md_dflags = le64dec(data + 87); + bcopy(data + 95, md->md_provider, 16); + md->md_provsize = le64dec(data + 111); + bcopy(data + 119, md->md_hash, 16); + + errno_t rc = create_hash(data, 119, md5_hash, HASH_MD5); + assert(rc == EOK); + memcpy(md->md_hash, data + 119, 16); + if (memcmp(md->md_hash, data + 119, 16) != 0) + return (EINVAL); + + return (0); +} +static __inline int +mirror_metadata_decode(const u_char *data, struct g_mirror_metadata *md) +{ + int error; + + bcopy(data, md->md_magic, 16); + md->md_version = le32dec(data + 16); + switch (md->md_version) { + case 4: + error = mirror_metadata_decode_v3v4(data, md); + break; + default: + error = EINVAL; + break; + } + return (error); +} + +static __inline const char * +balance_name(u_int balance) +{ + static const char *algorithms[] = { + [G_MIRROR_BALANCE_NONE] = "none", + [G_MIRROR_BALANCE_ROUND_ROBIN] = "round-robin", + [G_MIRROR_BALANCE_LOAD] = "load", + [G_MIRROR_BALANCE_SPLIT] = "split", + [G_MIRROR_BALANCE_PREFER] = "prefer", + [G_MIRROR_BALANCE_MAX + 1] = "unknown" + }; + + if (balance > G_MIRROR_BALANCE_MAX) + balance = G_MIRROR_BALANCE_MAX + 1; + + return (algorithms[balance]); +} + +static __inline int +balance_id(const char *name) +{ + static const char *algorithms[] = { + [G_MIRROR_BALANCE_NONE] = "none", + [G_MIRROR_BALANCE_ROUND_ROBIN] = "round-robin", + [G_MIRROR_BALANCE_LOAD] = "load", + [G_MIRROR_BALANCE_SPLIT] = "split", + [G_MIRROR_BALANCE_PREFER] = "prefer" + }; + int n; + + for (n = G_MIRROR_BALANCE_MIN; n <= G_MIRROR_BALANCE_MAX; n++) { + if (str_cmp(name, algorithms[n]) == 0) + return (n); + } + return (-1); +} + +static __inline void +mirror_metadata_dump(const struct g_mirror_metadata *md) +{ + static const char hex[] = "0123456789abcdef"; + char hash[16 * 2 + 1]; + u_int i; + + printf(" magic: %s\n", md->md_magic); + printf(" version: %u\n", (u_int)md->md_version); + printf(" name: %s\n", md->md_name); + printf(" mid: %u\n", (u_int)md->md_mid); + printf(" did: %u\n", (u_int)md->md_did); + printf(" all: %u\n", (u_int)md->md_all); + printf(" genid: %u\n", (u_int)md->md_genid); + printf(" syncid: %u\n", (u_int)md->md_syncid); + printf(" priority: %u\n", (u_int)md->md_priority); + printf(" slice: %u\n", (u_int)md->md_slice); + printf(" balance: %s\n", balance_name((u_int)md->md_balance)); + printf(" mediasize: %jd\n", (intmax_t)md->md_mediasize); + printf("sectorsize: %u\n", (u_int)md->md_sectorsize); + printf("syncoffset: %jd\n", (intmax_t)md->md_sync_offset); + printf(" mflags:"); + if (md->md_mflags == 0) + printf(" NONE"); + else { + if ((md->md_mflags & G_MIRROR_DEVICE_FLAG_NOFAILSYNC) != 0) + printf(" NOFAILSYNC"); + if ((md->md_mflags & G_MIRROR_DEVICE_FLAG_NOAUTOSYNC) != 0) + printf(" NOAUTOSYNC"); + } + printf("\n"); + printf(" dflags:"); + if (md->md_dflags == 0) + printf(" NONE"); + else { + if ((md->md_dflags & G_MIRROR_DISK_FLAG_DIRTY) != 0) + printf(" DIRTY"); + if ((md->md_dflags & G_MIRROR_DISK_FLAG_SYNCHRONIZING) != 0) + printf(" SYNCHRONIZING"); + if ((md->md_dflags & G_MIRROR_DISK_FLAG_FORCE_SYNC) != 0) + printf(" FORCE_SYNC"); + if ((md->md_dflags & G_MIRROR_DISK_FLAG_INACTIVE) != 0) + printf(" INACTIVE"); + } + printf("\n"); + printf("hcprovider: %s\n", md->md_provider); + printf(" provsize: %ju\n", (uintmax_t)md->md_provsize); + /* bzero(hash, sizeof(hash)); */ + memset(hash, 0, sizeof(hash)); + + for (i = 0; i < 16; i++) { + hash[i * 2] = hex[md->md_hash[i] >> 4]; + hash[i * 2 + 1] = hex[md->md_hash[i] & 0x0f]; + } + printf(" MD5 hash: %s\n", hash); +} + +#endif + +/** @} + */ diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/mirror.c b/uspace/srv/bd/hr/metadata/foreign/geom/mirror.c new file mode 100644 index 0000000000..18a798b8c2 --- /dev/null +++ b/uspace/srv/bd/hr/metadata/foreign/geom/mirror.c @@ -0,0 +1,393 @@ +/* + * 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 +#include +#include +#include +#include + +#include "../../../util.h" +#include "../../../var.h" + +#include "g_mirror.h" + +static void *meta_gmirror_alloc_struct(void); +static errno_t meta_gmirror_init_vol2meta(const hr_volume_t *, void *); +static errno_t meta_gmirror_init_meta2vol(const list_t *, + hr_volume_t *); +static void meta_gmirror_encode(void *, void *); +static errno_t meta_gmirror_decode(const void *, void *); +static errno_t meta_gmirror_get_block(service_id_t, void **); +static errno_t meta_gmirror_write_block(service_id_t, const void *); +static bool meta_gmirror_has_valid_magic(const void *); +static bool meta_gmirror_compare_uuids(const void *, const void *); +static void meta_gmirror_inc_counter(void *); +static errno_t meta_gmirror_save(hr_volume_t *, bool); +static const char *meta_gmirror_get_devname(const void *); +static hr_level_t meta_gmirror_get_level(const void *); +static uint64_t meta_gmirror_get_data_offset(void); +static size_t meta_gmirror_get_size(void); +static uint8_t meta_gmirror_get_flags(void); +static metadata_type_t meta_gmirror_get_type(void); +static void meta_gmirror_dump(const void *); + +hr_superblock_ops_t metadata_gmirror_ops = { + .alloc_struct = meta_gmirror_alloc_struct, + .init_vol2meta = meta_gmirror_init_vol2meta, + .init_meta2vol = meta_gmirror_init_meta2vol, + .encode = meta_gmirror_encode, + .decode = meta_gmirror_decode, + .get_block = meta_gmirror_get_block, + .write_block = meta_gmirror_write_block, + .has_valid_magic = meta_gmirror_has_valid_magic, + .compare_uuids = meta_gmirror_compare_uuids, + .inc_counter = meta_gmirror_inc_counter, + .save = meta_gmirror_save, + .get_devname = meta_gmirror_get_devname, + .get_level = meta_gmirror_get_level, + .get_data_offset = meta_gmirror_get_data_offset, + .get_size = meta_gmirror_get_size, + .get_flags = meta_gmirror_get_flags, + .get_type = meta_gmirror_get_type, + .dump = meta_gmirror_dump +}; + +static void *meta_gmirror_alloc_struct(void) +{ + return calloc(1, sizeof(struct g_mirror_metadata)); +} + +static errno_t meta_gmirror_init_vol2meta(const hr_volume_t *vol, void *md_v) +{ + (void)vol; + (void)md_v; + return ENOTSUP; +} + +static errno_t meta_gmirror_init_meta2vol(const list_t *list, hr_volume_t *vol) +{ + HR_DEBUG("%s()", __func__); + + errno_t rc = EOK; + + struct g_mirror_metadata *main_meta = NULL; + size_t max_counter_val = 0; + + list_foreach(*list, link, struct dev_list_member, iter) { + struct g_mirror_metadata *iter_meta = iter->md; + + if (iter_meta->md_genid >= max_counter_val) { + max_counter_val = iter_meta->md_genid; + main_meta = iter_meta; + } + } + + assert(main_meta != NULL); + + vol->truncated_blkno = + main_meta->md_mediasize / main_meta->md_sectorsize; + + vol->data_blkno = vol->truncated_blkno - 1; + + vol->data_offset = 0; + + if (main_meta->md_all > HR_MAX_EXTENTS) { + HR_DEBUG("Assembled volume has %u extents (max = %u)", + (unsigned)main_meta->md_all, HR_MAX_EXTENTS); + rc = EINVAL; + goto error; + } + + vol->extent_no = main_meta->md_all; + + /* vol->layout = main_meta->layout; */ + + /* vol->strip_size = main_meta->strip_size; */ + + vol->bsize = main_meta->md_sectorsize; + + memcpy(vol->in_mem_md, main_meta, sizeof(struct g_mirror_metadata)); + + uint8_t index = 0; + list_foreach(*list, link, struct dev_list_member, iter) { + struct g_mirror_metadata *iter_meta = iter->md; + + vol->extents[index].svc_id = iter->svc_id; + + uint64_t blkno; + rc = block_get_nblocks(iter->svc_id, &blkno); + if (rc != EOK) + goto error; + + vol->extents[index].blkno = blkno; + + if (iter_meta->md_genid == max_counter_val) + vol->extents[index].status = HR_EXT_ONLINE; + else + vol->extents[index].status = HR_EXT_INVALID; + + index++; + } + + for (size_t i = 0; i < vol->extent_no; i++) { + if (vol->extents[i].status == HR_EXT_NONE) + vol->extents[i].status = HR_EXT_MISSING; + } + +error: + return rc; +} + +static void meta_gmirror_encode(void *md_v, void *block) +{ + HR_DEBUG("%s()", __func__); + + mirror_metadata_encode(md_v, block); +} + +static errno_t meta_gmirror_decode(const void *block, void *md_v) +{ + HR_DEBUG("%s()", __func__); + + errno_t rc = mirror_metadata_decode(block, md_v); + return rc; +} + +static errno_t meta_gmirror_get_block(service_id_t dev, void **rblock) +{ + HR_DEBUG("%s()", __func__); + + errno_t rc; + uint64_t blkno; + size_t bsize; + void *block; + + if (rblock == NULL) + return EINVAL; + + rc = block_get_bsize(dev, &bsize); + if (rc != EOK) + return rc; + + if (bsize < sizeof(struct g_mirror_metadata)) + return EINVAL; + + rc = block_get_nblocks(dev, &blkno); + if (rc != EOK) + return rc; + + if (blkno < 1) + return EINVAL; + + block = malloc(bsize); + if (block == NULL) + return ENOMEM; + + rc = block_read_direct(dev, blkno - 1, 1, block); + /* + * XXX: here maybe call vol status event or the state callback... + * + * but need to pass vol pointer + */ + if (rc != EOK) { + free(block); + return rc; + } + + *rblock = block; + return EOK; +} + +static errno_t meta_gmirror_write_block(service_id_t dev, const void *block) +{ + HR_DEBUG("%s()", __func__); + + errno_t rc; + uint64_t blkno; + size_t bsize; + + rc = block_get_bsize(dev, &bsize); + if (rc != EOK) + return rc; + + if (bsize < sizeof(struct g_mirror_metadata)) + return EINVAL; + + rc = block_get_nblocks(dev, &blkno); + if (rc != EOK) + return rc; + + if (blkno < 1) + return EINVAL; + + rc = block_write_direct(dev, blkno - 1, 1, block); + + return rc; +} + +static bool meta_gmirror_has_valid_magic(const void *md_v) +{ + HR_DEBUG("%s()", __func__); + + const struct g_mirror_metadata *md = md_v; + + if (str_lcmp(md->md_magic, G_MIRROR_MAGIC, 16) != 0) + return false; + + return true; +} + +static bool meta_gmirror_compare_uuids(const void *m1_v, const void *m2_v) +{ + const struct g_mirror_metadata *m1 = m1_v; + const struct g_mirror_metadata *m2 = m2_v; + if (m1->md_mid == m2->md_mid) + return true; + + return false; +} + +static void meta_gmirror_inc_counter(void *md_v) +{ + struct g_mirror_metadata *md = md_v; + + /* XXX: probably md_genid and not md_syncid is incremented */ + md->md_genid++; +} + +/* + * XXX: finish this fcn documentation + * + * Returns ENOMEM else EOK + */ +static errno_t meta_gmirror_save(hr_volume_t *vol, bool with_state_callback) +{ + HR_DEBUG("%s()", __func__); + + errno_t rc = EOK; + + void *md_block = calloc(1, vol->bsize); + if (md_block == NULL) + return ENOMEM; + + struct g_mirror_metadata *md = vol->in_mem_md; + + fibril_rwlock_read_lock(&vol->extents_lock); + + fibril_mutex_lock(&vol->md_lock); + + for (size_t i = 0; i < vol->extent_no; i++) { + hr_extent_t *ext = &vol->extents[i]; + + fibril_rwlock_read_lock(&vol->states_lock); + + /* TODO: special case for REBUILD */ + if (ext->status != HR_EXT_ONLINE) + continue; + + fibril_rwlock_read_unlock(&vol->states_lock); + + md->md_priority = i; + meta_gmirror_encode(md, md_block); + rc = meta_gmirror_write_block(ext->svc_id, md_block); + if (with_state_callback && rc != EOK) + vol->state_callback(vol, i, rc); + } + + fibril_mutex_unlock(&vol->md_lock); + + fibril_rwlock_read_unlock(&vol->extents_lock); + + if (with_state_callback) + vol->hr_ops.status_event(vol); + + free(md_block); + return EOK; +} + +static const char *meta_gmirror_get_devname(const void *md_v) +{ + const struct g_mirror_metadata *md = md_v; + + return md->md_name; +} + +static hr_level_t meta_gmirror_get_level(const void *md_v) +{ + (void)md_v; + + return HR_LVL_1; +} + +static uint64_t meta_gmirror_get_data_offset(void) +{ + return 0; +} + +static size_t meta_gmirror_get_size(void) +{ + return 1; +} + +static uint8_t meta_gmirror_get_flags(void) +{ + uint8_t flags = 0; + + return flags; +} + +static metadata_type_t meta_gmirror_get_type(void) +{ + return HR_METADATA_GEOM_MIRROR; +} + +static void meta_gmirror_dump(const void *md_v) +{ + HR_DEBUG("%s()", __func__); + + mirror_metadata_dump(md_v); +} + +/** @} + */ diff --git a/uspace/srv/bd/hr/metadata/native.c b/uspace/srv/bd/hr/metadata/native.c index 2fdf2f4f57..5c27dff277 100644 --- a/uspace/srv/bd/hr/metadata/native.c +++ b/uspace/srv/bd/hr/metadata/native.c @@ -56,8 +56,8 @@ static void *meta_native_alloc_struct(void); static errno_t meta_native_init_vol2meta(const hr_volume_t *, void *); static errno_t meta_native_init_meta2vol(const list_t *, hr_volume_t *); -static void meta_native_encode(const void *, void *); -static void meta_native_decode(const void *, void *); +static void meta_native_encode(void *, void *); +static errno_t meta_native_decode(const void *, void *); static errno_t meta_native_get_block(service_id_t, void **); static errno_t meta_native_write_block(service_id_t, const void *); static bool meta_native_has_valid_magic(const void *); @@ -191,7 +191,7 @@ static errno_t meta_native_init_meta2vol(const list_t *list, hr_volume_t *vol) return rc; } -static void meta_native_encode(const void *md_v, void *block) +static void meta_native_encode(void *md_v, void *block) { HR_DEBUG("%s()", __func__); @@ -224,7 +224,7 @@ static void meta_native_encode(const void *md_v, void *block) memcpy(block, &scratch_md, sizeof(hr_metadata_t)); } -static void meta_native_decode(const void *block, void *md_v) +static errno_t meta_native_decode(const void *block, void *md_v) { HR_DEBUG("%s()", __func__); @@ -254,6 +254,8 @@ static void meta_native_decode(const void *block, void *md_v) metadata->strip_size = uint32_t_le2host(scratch_md.strip_size); metadata->bsize = uint32_t_le2host(scratch_md.bsize); memcpy(metadata->devname, scratch_md.devname, HR_DEVNAME_LEN); + + return EOK; } static errno_t meta_native_get_block(service_id_t dev, void **rblock) diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index 1df19cbc1a..05e9176908 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -45,15 +45,19 @@ #include #include -#include "metadata/native.h" #include "superblock.h" #include "util.h" #include "var.h" +#include "metadata/foreign/geom/g_mirror.h" +#include "metadata/native.h" + extern hr_superblock_ops_t metadata_native_ops; +extern hr_superblock_ops_t metadata_gmirror_ops; static hr_superblock_ops_t *hr_superblock_ops_all[] = { - [HR_METADATA_NATIVE] = &metadata_native_ops + [HR_METADATA_NATIVE] = &metadata_native_ops, + [HR_METADATA_GEOM_MIRROR] = &metadata_gmirror_ops }; hr_superblock_ops_t *get_type_ops(metadata_type_t type) @@ -95,10 +99,15 @@ errno_t find_metadata(service_id_t svc_id, void **rmetadata, continue; } - meta_ops->decode(meta_block, metadata_struct); + rc = meta_ops->decode(meta_block, metadata_struct); free(meta_block); + if (rc != EOK) { + free(metadata_struct); + continue; + } + if (!meta_ops->has_valid_magic(metadata_struct)) { free(metadata_struct); continue; diff --git a/uspace/srv/bd/hr/superblock.h b/uspace/srv/bd/hr/superblock.h index f67d891061..0f54114d93 100644 --- a/uspace/srv/bd/hr/superblock.h +++ b/uspace/srv/bd/hr/superblock.h @@ -42,7 +42,8 @@ typedef struct hr_volume hr_volume_t; typedef enum { HR_METADATA_NATIVE = 0, - HR_METADATA_LAST_DUMMY = 1 + HR_METADATA_GEOM_MIRROR = 1, + HR_METADATA_LAST_DUMMY = 2 } metadata_type_t; #define HR_METADATA_HOTSPARE_SUPPORT 0x01 @@ -51,8 +52,8 @@ typedef struct hr_superblock_ops { void *(*alloc_struct)(void); errno_t (*init_vol2meta)(const hr_volume_t *, void *); errno_t (*init_meta2vol)(const list_t *, hr_volume_t *); - void (*encode)(const void *, void *); - void (*decode)(const void *, void *); + void (*encode)(void *, void *); + errno_t (*decode)(const void *, void *); errno_t (*get_block)(service_id_t, void **); errno_t (*write_block)(service_id_t, const void *); bool (*has_valid_magic)(const void *); From f09b75b791ce37af542020b17496776f9ecdfa36 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 21 Apr 2025 14:24:11 +0200 Subject: [PATCH 186/324] hr: metadata/foreign/geom: add --- .../bd/hr/metadata/foreign/geom/g_mirror.h | 38 +---- .../bd/hr/metadata/foreign/geom/sys_endian.h | 139 ++++++++++++++++++ 2 files changed, 141 insertions(+), 36 deletions(-) create mode 100644 uspace/srv/bd/hr/metadata/foreign/geom/sys_endian.h diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/g_mirror.h b/uspace/srv/bd/hr/metadata/foreign/geom/g_mirror.h index 4a198a5dc6..b9667fb839 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/g_mirror.h +++ b/uspace/srv/bd/hr/metadata/foreign/geom/g_mirror.h @@ -46,42 +46,8 @@ typedef unsigned char u_char; typedef unsigned int u_int; #define bcopy(src, dst, len) memcpy(dst, src, len) -/* copied here from */ -static __inline void -le32enc(void *pp, uint32_t u) -{ - uint8_t *p = (uint8_t *)pp; - - p[0] = u & 0xff; - p[1] = (u >> 8) & 0xff; - p[2] = (u >> 16) & 0xff; - p[3] = (u >> 24) & 0xff; -} - -static __inline void -le64enc(void *pp, uint64_t u) -{ - uint8_t *p = (uint8_t *)pp; - - le32enc(p, (uint32_t)(u & 0xffffffffU)); - le32enc(p + 4, (uint32_t)(u >> 32)); -} - -static __inline uint32_t -le32dec(const void *pp) -{ - uint8_t const *p = (uint8_t const *)pp; - - return (((unsigned)p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]); -} - -static __inline uint64_t -le64dec(const void *pp) -{ - uint8_t const *p = (uint8_t const *)pp; - - return (((uint64_t)le32dec(p + 4) << 32) | le32dec(p)); -} +/* needed FreeBSD header */ +#include "sys_endian.h" /* here continues the stripped down original header */ diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/sys_endian.h b/uspace/srv/bd/hr/metadata/foreign/geom/sys_endian.h new file mode 100644 index 0000000000..e2e756c0ed --- /dev/null +++ b/uspace/srv/bd/hr/metadata/foreign/geom/sys_endian.h @@ -0,0 +1,139 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2002 Thomas Moestl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + */ + +#ifndef _HR_METADATA_FOREIGN_GEOM_SYS_ENDIAN_H +#define _HR_METADATA_FOREIGN_GEOM_SYS_ENDIAN_H + +/* Alignment-agnostic encode/decode bytestream to/from little/big endian. */ +static __inline uint16_t +be16dec(const void *pp) +{ + uint8_t const *p = (uint8_t const *)pp; + + return ((p[0] << 8) | p[1]); +} + +static __inline uint32_t +be32dec(const void *pp) +{ + uint8_t const *p = (uint8_t const *)pp; + + return (((unsigned)p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]); +} + +static __inline uint64_t +be64dec(const void *pp) +{ + uint8_t const *p = (uint8_t const *)pp; + + return (((uint64_t)be32dec(p) << 32) | be32dec(p + 4)); +} + +static __inline uint16_t +le16dec(const void *pp) +{ + uint8_t const *p = (uint8_t const *)pp; + + return ((p[1] << 8) | p[0]); +} + +static __inline uint32_t +le32dec(const void *pp) +{ + uint8_t const *p = (uint8_t const *)pp; + + return (((unsigned)p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]); +} + +static __inline uint64_t +le64dec(const void *pp) +{ + uint8_t const *p = (uint8_t const *)pp; + + return (((uint64_t)le32dec(p + 4) << 32) | le32dec(p)); +} + +static __inline void +be16enc(void *pp, uint16_t u) +{ + uint8_t *p = (uint8_t *)pp; + + p[0] = (u >> 8) & 0xff; + p[1] = u & 0xff; +} + +static __inline void +be32enc(void *pp, uint32_t u) +{ + uint8_t *p = (uint8_t *)pp; + + p[0] = (u >> 24) & 0xff; + p[1] = (u >> 16) & 0xff; + p[2] = (u >> 8) & 0xff; + p[3] = u & 0xff; +} + +static __inline void +be64enc(void *pp, uint64_t u) +{ + uint8_t *p = (uint8_t *)pp; + + be32enc(p, (uint32_t)(u >> 32)); + be32enc(p + 4, (uint32_t)(u & 0xffffffffU)); +} + +static __inline void +le16enc(void *pp, uint16_t u) +{ + uint8_t *p = (uint8_t *)pp; + + p[0] = u & 0xff; + p[1] = (u >> 8) & 0xff; +} + +static __inline void +le32enc(void *pp, uint32_t u) +{ + uint8_t *p = (uint8_t *)pp; + + p[0] = u & 0xff; + p[1] = (u >> 8) & 0xff; + p[2] = (u >> 16) & 0xff; + p[3] = (u >> 24) & 0xff; +} + +static __inline void +le64enc(void *pp, uint64_t u) +{ + uint8_t *p = (uint8_t *)pp; + + le32enc(p, (uint32_t)(u & 0xffffffffU)); + le32enc(p + 4, (uint32_t)(u >> 32)); +} + +#endif From 18c3658f8a41498843334b542c3dc46c5b4b57bf Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 21 Apr 2025 14:26:28 +0200 Subject: [PATCH 187/324] hr: raid{0,1,5}.c: unusable volume creation message --- uspace/srv/bd/hr/raid0.c | 5 ++++- uspace/srv/bd/hr/raid1.c | 5 ++++- uspace/srv/bd/hr/raid5.c | 2 ++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index 46ea5036b7..204848ca32 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -92,8 +92,11 @@ errno_t hr_raid0_create(hr_volume_t *new_volume) } hr_raid0_update_vol_status(new_volume); - if (new_volume->status != HR_VOL_ONLINE) + if (new_volume->status != HR_VOL_ONLINE) { + HR_NOTE("\"%s\": unusable state, not creating\n", + new_volume->devname); return EINVAL; + } bd_srvs_init(&new_volume->hr_bds); new_volume->hr_bds.ops = &hr_raid0_bd_ops; diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index faba34a428..e550547888 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -114,8 +114,11 @@ errno_t hr_raid1_create(hr_volume_t *new_volume) fibril_rwlock_read_lock(&new_volume->states_lock); hr_vol_status_t state = new_volume->status; fibril_rwlock_read_unlock(&new_volume->states_lock); - if (state == HR_VOL_FAULTY || state == HR_VOL_NONE) + if (state == HR_VOL_FAULTY || state == HR_VOL_NONE) { + HR_NOTE("\"%s\": unusable state, not creating\n", + new_volume->devname); return EINVAL; + } return EOK; } diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index be6ad1099f..847341a6a5 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -106,6 +106,8 @@ errno_t hr_raid5_create(hr_volume_t *new_volume) errno_t rc = hr_raid5_update_vol_status(new_volume); if (rc != EOK) { + HR_NOTE("\"%s\": unusable state, not creating\n", + new_volume->devname); fibril_rwlock_write_unlock(&new_volume->states_lock); return rc; } From 80c760ed213d036971c4ea809eab9ca1b0abae11 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 21 Apr 2025 14:34:02 +0200 Subject: [PATCH 188/324] hr: remove truncated_blkno calculation from raid*.c Calculate the initial truncated_blkno in hr_init_extents_from_cfg, allowing the removal of hr_extent_t.blkno. Also fixes double block_fini() on failed volume creation in hr_util_try_assemble(). --- uspace/lib/device/include/hr.h | 1 - .../srv/bd/hr/metadata/foreign/geom/mirror.c | 8 +----- uspace/srv/bd/hr/metadata/native.c | 13 ++-------- uspace/srv/bd/hr/raid0.c | 9 +------ uspace/srv/bd/hr/raid1.c | 9 +------ uspace/srv/bd/hr/raid5.c | 11 ++------ uspace/srv/bd/hr/util.c | 26 ++++++++----------- uspace/srv/bd/hr/util.h | 1 + 8 files changed, 19 insertions(+), 59 deletions(-) diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index ebec90ff2c..a17d81ab4b 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -98,7 +98,6 @@ typedef struct hr_config { typedef struct hr_extent { service_id_t svc_id; hr_ext_status_t status; - uint64_t blkno; } hr_extent_t; typedef struct hr_vol_info { diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/mirror.c b/uspace/srv/bd/hr/metadata/foreign/geom/mirror.c index 18a798b8c2..1f59718916 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/mirror.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/mirror.c @@ -154,13 +154,7 @@ static errno_t meta_gmirror_init_meta2vol(const list_t *list, hr_volume_t *vol) struct g_mirror_metadata *iter_meta = iter->md; vol->extents[index].svc_id = iter->svc_id; - - uint64_t blkno; - rc = block_get_nblocks(iter->svc_id, &blkno); - if (rc != EOK) - goto error; - - vol->extents[index].blkno = blkno; + iter->fini = false; if (iter_meta->md_genid == max_counter_val) vol->extents[index].status = HR_EXT_ONLINE; diff --git a/uspace/srv/bd/hr/metadata/native.c b/uspace/srv/bd/hr/metadata/native.c index 5c27dff277..def355f405 100644 --- a/uspace/srv/bd/hr/metadata/native.c +++ b/uspace/srv/bd/hr/metadata/native.c @@ -138,8 +138,6 @@ static errno_t meta_native_init_meta2vol(const list_t *list, hr_volume_t *vol) { HR_DEBUG("%s()", __func__); - errno_t rc = EOK; - hr_metadata_t *main_meta = NULL; size_t max_counter_val = 0; @@ -168,13 +166,7 @@ static errno_t meta_native_init_meta2vol(const list_t *list, hr_volume_t *vol) hr_metadata_t *iter_meta = (hr_metadata_t *)iter->md; vol->extents[iter_meta->index].svc_id = iter->svc_id; - - uint64_t blkno; - rc = block_get_nblocks(iter->svc_id, &blkno); - if (rc != EOK) - goto error; - - vol->extents[iter_meta->index].blkno = blkno; + iter->fini = false; if (iter_meta->counter == max_counter_val) vol->extents[iter_meta->index].status = HR_EXT_ONLINE; @@ -187,8 +179,7 @@ static errno_t meta_native_init_meta2vol(const list_t *list, hr_volume_t *vol) vol->extents[i].status = HR_EXT_MISSING; } -error: - return rc; + return EOK; } static void meta_native_encode(void *md_v, void *block) diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index 204848ca32..9b5146c0b0 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -116,15 +116,8 @@ errno_t hr_raid0_init(hr_volume_t *vol) assert(vol->level == HR_LVL_0); - uint64_t truncated_blkno = vol->extents[0].blkno; - for (size_t i = 1; i < vol->extent_no; i++) { - if (vol->extents[i].blkno < truncated_blkno) - truncated_blkno = vol->extents[i].blkno; - } - - uint64_t total_blkno = truncated_blkno * vol->extent_no; + uint64_t total_blkno = vol->truncated_blkno * vol->extent_no; - vol->truncated_blkno = truncated_blkno; vol->data_offset = vol->meta_ops->get_data_offset(); vol->data_blkno = total_blkno; diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index e550547888..aedc42ca48 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -132,15 +132,8 @@ errno_t hr_raid1_init(hr_volume_t *vol) assert(vol->level == HR_LVL_1); - uint64_t truncated_blkno = vol->extents[0].blkno; - for (size_t i = 1; i < vol->extent_no; i++) { - if (vol->extents[i].blkno < truncated_blkno) - truncated_blkno = vol->extents[i].blkno; - } - - vol->truncated_blkno = truncated_blkno; vol->data_offset = vol->meta_ops->get_data_offset(); - vol->data_blkno = truncated_blkno - vol->meta_ops->get_size(); + vol->data_blkno = vol->truncated_blkno - vol->meta_ops->get_size(); vol->strip_size = 0; return EOK; diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 847341a6a5..445e1557e2 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -130,21 +130,14 @@ errno_t hr_raid5_init(hr_volume_t *vol) assert(vol->level == HR_LVL_5 || vol->level == HR_LVL_4); - uint64_t truncated_blkno = vol->extents[0].blkno; - for (size_t i = 1; i < vol->extent_no; i++) { - if (vol->extents[i].blkno < truncated_blkno) - truncated_blkno = vol->extents[i].blkno; - } - - uint64_t total_blkno = truncated_blkno * vol->extent_no; + uint64_t total_blkno = vol->truncated_blkno * vol->extent_no; - vol->truncated_blkno = truncated_blkno; vol->data_offset = vol->meta_ops->get_data_offset(); vol->data_blkno = total_blkno; /* count md blocks */ vol->data_blkno -= vol->meta_ops->get_size() * vol->extent_no; - vol->data_blkno -= truncated_blkno; /* count parity */ + vol->data_blkno -= vol->truncated_blkno; /* count parity */ vol->strip_size = HR_STRIP_SIZE; diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 2da4e06e25..c9319c3a0e 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -233,7 +233,7 @@ errno_t hr_init_extents_from_cfg(hr_volume_t *vol, hr_config_t *cfg) HR_DEBUG("%s()", __func__); errno_t rc; - uint64_t blkno; + uint64_t blkno, smallest_blkno = ~0ULL; size_t i, bsize; size_t last_bsize = 0; @@ -268,14 +268,16 @@ errno_t hr_init_extents_from_cfg(hr_volume_t *vol, hr_config_t *cfg) } vol->extents[i].svc_id = svc_id; - vol->extents[i].blkno = blkno; vol->extents[i].status = HR_EXT_ONLINE; + if (blkno < smallest_blkno) + smallest_blkno = blkno; last_bsize = bsize; } vol->bsize = last_bsize; vol->extent_no = cfg->dev_no; + vol->truncated_blkno = smallest_blkno; for (i = 0; i < HR_MAX_HOTSPARES; i++) vol->hotspares[i].status = HR_EXT_MISSING; @@ -727,6 +729,7 @@ static errno_t block_init_dev_list(list_t *list) return rc; iter->inited = true; + iter->fini = true; } return EOK; @@ -737,9 +740,10 @@ static void block_fini_dev_list(list_t *list) HR_DEBUG("%s()", __func__); list_foreach(*list, link, struct dev_list_member, iter) { - if (iter->inited) { + if (iter->inited && iter->fini) { block_fini(iter->svc_id); iter->inited = false; + iter->fini = false; } } } @@ -982,20 +986,12 @@ errno_t hr_util_try_assemble(hr_config_t *cfg, size_t *rassembled_cnt) case EOK: asm_cnt++; break; - case EEXIST: - /* - * A race is detected this way, because we don't want - * to hold the hr_volumes list lock for a long time, - * for all assembly attempts. XXX: discuss... - */ - rc = EOK; - break; - default: - block_fini_dev_list(&matching_svcs_list); - free_svc_id_list(&matching_svcs_list); + case ENOMEM: goto error; + default: + rc = EOK; } - + block_fini_dev_list(&matching_svcs_list); free_svc_id_list(&matching_svcs_list); } diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index 7f6412e7b7..dc7eb34555 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -50,6 +50,7 @@ struct dev_list_member { void *md; bool inited; bool md_present; + bool fini; }; #define HR_DEBUG(format, ...) \ From 75262d2f4df86c88815e7c9adb7fbc885c5da692 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 21 Apr 2025 14:37:19 +0200 Subject: [PATCH 189/324] hr: util.c: hr_create_vol_struct() style --- uspace/srv/bd/hr/util.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index c9319c3a0e..f072730e68 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -89,6 +89,8 @@ errno_t hr_create_vol_struct(hr_volume_t **rvol, hr_level_t level, vol->meta_ops = get_type_ops(metadata_type); + uint8_t meta_flags = vol->meta_ops->get_flags(); + switch (level) { case HR_LVL_0: vol->hr_ops.create = hr_raid0_create; @@ -99,21 +101,21 @@ errno_t hr_create_vol_struct(hr_volume_t **rvol, hr_level_t level, vol->hr_ops.create = hr_raid1_create; vol->hr_ops.init = hr_raid1_init; vol->hr_ops.status_event = hr_raid1_status_event; - if (vol->meta_ops->get_flags() & HR_METADATA_HOTSPARE_SUPPORT) + if (meta_flags & HR_METADATA_HOTSPARE_SUPPORT) vol->hr_ops.add_hotspare = hr_raid1_add_hotspare; break; case HR_LVL_4: vol->hr_ops.create = hr_raid5_create; vol->hr_ops.init = hr_raid5_init; vol->hr_ops.status_event = hr_raid5_status_event; - if (vol->meta_ops->get_flags() & HR_METADATA_HOTSPARE_SUPPORT) + if (meta_flags & HR_METADATA_HOTSPARE_SUPPORT) vol->hr_ops.add_hotspare = hr_raid5_add_hotspare; break; case HR_LVL_5: vol->hr_ops.create = hr_raid5_create; vol->hr_ops.init = hr_raid5_init; vol->hr_ops.status_event = hr_raid5_status_event; - if (vol->meta_ops->get_flags() & HR_METADATA_HOTSPARE_SUPPORT) + if (meta_flags & HR_METADATA_HOTSPARE_SUPPORT) vol->hr_ops.add_hotspare = hr_raid5_add_hotspare; break; default: From b883aa879e58aa6fb76e4bd0f1781f96cdb28c98 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 21 Apr 2025 14:47:58 +0200 Subject: [PATCH 190/324] hr: move metadata_type_t to lib/hr for type printing Also renames metadata_type_t -> hr_metadata_type_t. --- uspace/lib/device/include/hr.h | 8 +++++++ uspace/lib/device/src/hr.c | 14 ++++++++++++ .../srv/bd/hr/metadata/foreign/geom/mirror.c | 4 ++-- uspace/srv/bd/hr/metadata/native.c | 4 ++-- uspace/srv/bd/hr/superblock.c | 6 ++--- uspace/srv/bd/hr/superblock.h | 12 +++------- uspace/srv/bd/hr/util.c | 22 +++++++++---------- uspace/srv/bd/hr/util.h | 2 +- 8 files changed, 44 insertions(+), 28 deletions(-) diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index a17d81ab4b..8eb78cc403 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -114,6 +114,13 @@ typedef struct hr_vol_info { uint8_t layout; } hr_vol_info_t; +typedef enum { + HR_METADATA_NATIVE = 0, + HR_METADATA_GEOM_MIRROR = 1, + HR_METADATA_GEOM_STRIPE = 2, + HR_METADATA_LAST_DUMMY = 3 +} hr_metadata_type_t; + extern errno_t hr_sess_init(hr_t **); extern void hr_sess_destroy(hr_t *); extern errno_t hr_create(hr_t *, hr_config_t *); @@ -125,6 +132,7 @@ extern errno_t hr_print_status(void); extern const char *hr_get_vol_status_msg(hr_vol_status_t); extern const char *hr_get_ext_status_msg(hr_ext_status_t); extern const char *hr_get_layout_str(hr_level_t, uint8_t); +extern const char *hr_get_metadata_type_str(hr_metadata_type_t); #endif diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index 7e79581ab3..8e21479b7c 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -455,5 +455,19 @@ const char *hr_get_layout_str(hr_level_t level, uint8_t layout) } } +const char *hr_get_metadata_type_str(hr_metadata_type_t type) +{ + switch (type) { + case HR_METADATA_NATIVE: + return "Native HelenRAID metadata"; + case HR_METADATA_GEOM_MIRROR: + return "GEOM::MIRROR"; + case HR_METADATA_GEOM_STRIPE: + return "GEOM::STRIPE"; + default: + return "Invalid metadata type value"; + } +} + /** @} */ diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/mirror.c b/uspace/srv/bd/hr/metadata/foreign/geom/mirror.c index 1f59718916..43863dc3e7 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/mirror.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/mirror.c @@ -69,7 +69,7 @@ static hr_level_t meta_gmirror_get_level(const void *); static uint64_t meta_gmirror_get_data_offset(void); static size_t meta_gmirror_get_size(void); static uint8_t meta_gmirror_get_flags(void); -static metadata_type_t meta_gmirror_get_type(void); +static hr_metadata_type_t meta_gmirror_get_type(void); static void meta_gmirror_dump(const void *); hr_superblock_ops_t metadata_gmirror_ops = { @@ -371,7 +371,7 @@ static uint8_t meta_gmirror_get_flags(void) return flags; } -static metadata_type_t meta_gmirror_get_type(void) +static hr_metadata_type_t meta_gmirror_get_type(void) { return HR_METADATA_GEOM_MIRROR; } diff --git a/uspace/srv/bd/hr/metadata/native.c b/uspace/srv/bd/hr/metadata/native.c index def355f405..6456e45a81 100644 --- a/uspace/srv/bd/hr/metadata/native.c +++ b/uspace/srv/bd/hr/metadata/native.c @@ -69,7 +69,7 @@ static hr_level_t meta_native_get_level(const void *); static uint64_t meta_native_get_data_offset(void); static size_t meta_native_get_size(void); static uint8_t meta_native_get_flags(void); -static metadata_type_t meta_native_get_type(void); +static hr_metadata_type_t meta_native_get_type(void); static void meta_native_dump(const void *); hr_superblock_ops_t metadata_native_ops = { @@ -433,7 +433,7 @@ static uint8_t meta_native_get_flags(void) return flags; } -static metadata_type_t meta_native_get_type(void) +static hr_metadata_type_t meta_native_get_type(void) { return HR_METADATA_NATIVE; } diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index 05e9176908..60ee55933c 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -60,7 +60,7 @@ static hr_superblock_ops_t *hr_superblock_ops_all[] = { [HR_METADATA_GEOM_MIRROR] = &metadata_gmirror_ops }; -hr_superblock_ops_t *get_type_ops(metadata_type_t type) +hr_superblock_ops_t *get_type_ops(hr_metadata_type_t type) { assert(type >= HR_METADATA_NATIVE && type < HR_METADATA_LAST_DUMMY); @@ -68,7 +68,7 @@ hr_superblock_ops_t *get_type_ops(metadata_type_t type) } errno_t find_metadata(service_id_t svc_id, void **rmetadata, - metadata_type_t *rtype) + hr_metadata_type_t *rtype) { HR_DEBUG("%s()", __func__); @@ -82,7 +82,7 @@ errno_t find_metadata(service_id_t svc_id, void **rmetadata, if (rtype == NULL) return EINVAL; - volatile metadata_type_t type = HR_METADATA_NATIVE; + volatile hr_metadata_type_t type = HR_METADATA_NATIVE; for (; type < HR_METADATA_LAST_DUMMY; type++) { meta_ops = hr_superblock_ops_all[type]; diff --git a/uspace/srv/bd/hr/superblock.h b/uspace/srv/bd/hr/superblock.h index 0f54114d93..c866679b83 100644 --- a/uspace/srv/bd/hr/superblock.h +++ b/uspace/srv/bd/hr/superblock.h @@ -40,12 +40,6 @@ typedef struct hr_volume hr_volume_t; -typedef enum { - HR_METADATA_NATIVE = 0, - HR_METADATA_GEOM_MIRROR = 1, - HR_METADATA_LAST_DUMMY = 2 -} metadata_type_t; - #define HR_METADATA_HOTSPARE_SUPPORT 0x01 typedef struct hr_superblock_ops { @@ -65,12 +59,12 @@ typedef struct hr_superblock_ops { uint64_t (*get_data_offset)(void); size_t (*get_size)(void); uint8_t (*get_flags)(void); - metadata_type_t (*get_type)(void); void (*dump)(const void *); + hr_metadata_type_t (*get_type)(void); } hr_superblock_ops_t; -hr_superblock_ops_t *get_type_ops(metadata_type_t); -extern errno_t find_metadata(service_id_t, void **, metadata_type_t *); +extern hr_superblock_ops_t *get_type_ops(hr_metadata_type_t); +extern errno_t find_metadata(service_id_t, void **, hr_metadata_type_t *); #endif diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index f072730e68..285da53e78 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -63,8 +63,8 @@ static errno_t hr_fill_disk_part_svcs_list(list_t *); static errno_t block_init_dev_list(list_t *); static void block_fini_dev_list(list_t *); static errno_t hr_util_get_matching_md_svcs_list(list_t *, list_t *, - service_id_t, metadata_type_t, void *); -static errno_t hr_util_assemble_from_matching_list(list_t *, metadata_type_t); + service_id_t, hr_metadata_type_t, void *); +static errno_t hr_util_assemble_from_matching_list(list_t *, hr_metadata_type_t); static errno_t hr_fill_svcs_list_from_cfg(hr_config_t *, list_t *); #define HR_RL_LIST_LOCK(vol) (fibril_mutex_lock(&(vol)->range_lock_list_lock)) @@ -76,7 +76,7 @@ extern list_t hr_volumes; extern fibril_rwlock_t hr_volumes_lock; errno_t hr_create_vol_struct(hr_volume_t **rvol, hr_level_t level, - const char *devname, metadata_type_t metadata_type) + const char *devname, hr_metadata_type_t metadata_type) { errno_t rc; @@ -751,7 +751,8 @@ static void block_fini_dev_list(list_t *list) } static errno_t hr_util_get_matching_md_svcs_list(list_t *rlist, list_t *list, - service_id_t svc_id, metadata_type_t type_main, void *metadata_struct_main) + service_id_t svc_id, hr_metadata_type_t type_main, + void *metadata_struct_main) { HR_DEBUG("%s()", __func__); @@ -764,7 +765,7 @@ static errno_t hr_util_get_matching_md_svcs_list(list_t *rlist, list_t *list, continue; void *metadata_struct; - metadata_type_t type; + hr_metadata_type_t type; rc = find_metadata(iter->svc_id, &metadata_struct, &type); if (rc == ENOFS) @@ -796,7 +797,7 @@ static errno_t hr_util_get_matching_md_svcs_list(list_t *rlist, list_t *list, } static errno_t hr_util_assemble_from_matching_list(list_t *list, - metadata_type_t type) + hr_metadata_type_t type) { HR_DEBUG("%s()", __func__); @@ -929,7 +930,7 @@ errno_t hr_util_try_assemble(hr_config_t *cfg, size_t *rassembled_cnt) iter = list_pop(&dev_id_list, struct dev_list_member, link); void *metadata_struct_main; - metadata_type_t type; + hr_metadata_type_t type; rc = find_metadata(iter->svc_id, &metadata_struct_main, &type); if (rc == ENOFS) { @@ -946,10 +947,9 @@ errno_t hr_util_try_assemble(hr_config_t *cfg, size_t *rassembled_cnt) rc = loc_service_get_name(iter->svc_id, &svc_name); if (rc != EOK) goto error; - - HR_DEBUG("found valid metadata on %s, " - "will try to match other extents\n", svc_name); - + HR_DEBUG("found valid metadata on %s (type = %s), matching " + "other extents\n", + svc_name, hr_get_metadata_type_str(type)); free(svc_name); list_t matching_svcs_list; diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index dc7eb34555..52e0273a57 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -67,7 +67,7 @@ struct dev_list_member { extern errno_t hr_create_vol_struct(hr_volume_t **, hr_level_t, - const char *, metadata_type_t); + const char *, hr_metadata_type_t); extern void hr_destroy_vol_struct(hr_volume_t *); extern hr_volume_t *hr_get_volume(service_id_t); extern errno_t hr_remove_volume(service_id_t); From 5cb16316d9a64fc20ee0a0576c6fdb13b9a710fc Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 21 Apr 2025 14:50:28 +0200 Subject: [PATCH 191/324] hr: FreeBSD GEOM::STRIPE metadata support --- uspace/srv/bd/hr/meson.build | 1 + .../bd/hr/metadata/foreign/geom/g_stripe.h | 102 +++++ .../srv/bd/hr/metadata/foreign/geom/stripe.c | 354 ++++++++++++++++++ uspace/srv/bd/hr/superblock.c | 5 +- 4 files changed, 461 insertions(+), 1 deletion(-) create mode 100644 uspace/srv/bd/hr/metadata/foreign/geom/g_stripe.h create mode 100644 uspace/srv/bd/hr/metadata/foreign/geom/stripe.c diff --git a/uspace/srv/bd/hr/meson.build b/uspace/srv/bd/hr/meson.build index f59b1552c9..c151abaf79 100644 --- a/uspace/srv/bd/hr/meson.build +++ b/uspace/srv/bd/hr/meson.build @@ -32,6 +32,7 @@ src = files( 'hr.c', 'io.c', 'metadata/foreign/geom/mirror.c', + 'metadata/foreign/geom/stripe.c', 'metadata/native.c', 'raid0.c', 'raid1.c', diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/g_stripe.h b/uspace/srv/bd/hr/metadata/foreign/geom/g_stripe.h new file mode 100644 index 0000000000..8495142d6b --- /dev/null +++ b/uspace/srv/bd/hr/metadata/foreign/geom/g_stripe.h @@ -0,0 +1,102 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2004-2005 Pawel Jakub Dawidek + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``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 AUTHORS OR CONTRIBUTORS 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 + */ + +#ifndef _HR_METADATA_FOREIGN_GEOM_STRIPE_H +#define _HR_METADATA_FOREIGN_GEOM_STRIPE_H + +/* needed HelenOS headers */ +#include +#include +#include + +/* new typedefs */ +typedef unsigned char u_char; +typedef unsigned int u_int; +#define bcopy(src, dst, len) memcpy(dst, src, len) + +/* needed FreeBSD header */ +#include "sys_endian.h" + +/* here continues the stripped down original header */ + +#define G_STRIPE_MAGIC "GEOM::STRIPE" + +#define G_STRIPE_VERSION 3 + +struct g_stripe_metadata { + char md_magic[16]; /* Magic value. */ + uint32_t md_version; /* Version number. */ + char md_name[16]; /* Stripe name. */ + uint32_t md_id; /* Unique ID. */ + uint16_t md_no; /* Disk number. */ + uint16_t md_all; /* Number of all disks. */ + uint32_t md_stripesize; /* Stripe size. */ + char md_provider[16]; /* Hardcoded provider. */ + uint64_t md_provsize; /* Provider's size. */ +}; + +static __inline void +stripe_metadata_encode(const struct g_stripe_metadata *md, u_char *data) +{ + + bcopy(md->md_magic, data, sizeof(md->md_magic)); + le32enc(data + 16, md->md_version); + bcopy(md->md_name, data + 20, sizeof(md->md_name)); + le32enc(data + 36, md->md_id); + le16enc(data + 40, md->md_no); + le16enc(data + 42, md->md_all); + le32enc(data + 44, md->md_stripesize); + bcopy(md->md_provider, data + 48, sizeof(md->md_provider)); + le64enc(data + 64, md->md_provsize); +} +static __inline void +stripe_metadata_decode(const u_char *data, struct g_stripe_metadata *md) +{ + + bcopy(data, md->md_magic, sizeof(md->md_magic)); + md->md_version = le32dec(data + 16); + bcopy(data + 20, md->md_name, sizeof(md->md_name)); + md->md_id = le32dec(data + 36); + md->md_no = le16dec(data + 40); + md->md_all = le16dec(data + 42); + md->md_stripesize = le32dec(data + 44); + bcopy(data + 48, md->md_provider, sizeof(md->md_provider)); + md->md_provsize = le64dec(data + 64); +} + +#endif + +/** @} + */ diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/stripe.c b/uspace/srv/bd/hr/metadata/foreign/geom/stripe.c new file mode 100644 index 0000000000..c47e69e11f --- /dev/null +++ b/uspace/srv/bd/hr/metadata/foreign/geom/stripe.c @@ -0,0 +1,354 @@ +/* + * 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 +#include +#include +#include +#include + +#include "../../../util.h" +#include "../../../var.h" + +#include "g_stripe.h" + +static void *meta_stripe_alloc_struct(void); +static errno_t meta_stripe_init_vol2meta(const hr_volume_t *, void *); +static errno_t meta_stripe_init_meta2vol(const list_t *, + hr_volume_t *); +static void meta_stripe_encode(void *, void *); +static errno_t meta_stripe_decode(const void *, void *); +static errno_t meta_stripe_get_block(service_id_t, void **); +static errno_t meta_stripe_write_block(service_id_t, const void *); +static bool meta_stripe_has_valid_magic(const void *); +static bool meta_stripe_compare_uuids(const void *, const void *); +static void meta_stripe_inc_counter(void *); +static errno_t meta_stripe_save(hr_volume_t *, bool); +static const char *meta_stripe_get_devname(const void *); +static hr_level_t meta_stripe_get_level(const void *); +static uint64_t meta_stripe_get_data_offset(void); +static size_t meta_stripe_get_size(void); +static uint8_t meta_stripe_get_flags(void); +static hr_metadata_type_t meta_stripe_get_type(void); +static void meta_stripe_dump(const void *); + +hr_superblock_ops_t metadata_stripe_ops = { + .alloc_struct = meta_stripe_alloc_struct, + .init_vol2meta = meta_stripe_init_vol2meta, + .init_meta2vol = meta_stripe_init_meta2vol, + .encode = meta_stripe_encode, + .decode = meta_stripe_decode, + .get_block = meta_stripe_get_block, + .write_block = meta_stripe_write_block, + .has_valid_magic = meta_stripe_has_valid_magic, + .compare_uuids = meta_stripe_compare_uuids, + .inc_counter = meta_stripe_inc_counter, + .save = meta_stripe_save, + .get_devname = meta_stripe_get_devname, + .get_level = meta_stripe_get_level, + .get_data_offset = meta_stripe_get_data_offset, + .get_size = meta_stripe_get_size, + .get_flags = meta_stripe_get_flags, + .get_type = meta_stripe_get_type, + .dump = meta_stripe_dump +}; + +static void *meta_stripe_alloc_struct(void) +{ + return calloc(1, sizeof(struct g_stripe_metadata)); +} + +static errno_t meta_stripe_init_vol2meta(const hr_volume_t *vol, void *md_v) +{ + (void)vol; + (void)md_v; + return ENOTSUP; +} + +static errno_t meta_stripe_init_meta2vol(const list_t *list, hr_volume_t *vol) +{ + HR_DEBUG("%s()", __func__); + + errno_t rc = EOK; + + /* get bsize */ + size_t bsize; + struct dev_list_member *memb = list_get_instance(list_first(list), + struct dev_list_member, link); + rc = block_get_bsize(memb->svc_id, &bsize); + if (rc != EOK) + goto error; + + vol->bsize = bsize; + + uint64_t smallest_provider_size = ~0ULL; + struct g_stripe_metadata *main_meta = NULL; + + list_foreach(*list, link, struct dev_list_member, iter) { + struct g_stripe_metadata *iter_meta = iter->md; + + meta_stripe_dump(iter_meta); + + if (iter_meta->md_provsize < smallest_provider_size) { + smallest_provider_size = iter_meta->md_provsize; + main_meta = iter_meta; + } + } + + assert(main_meta != NULL); + + vol->truncated_blkno = + main_meta->md_provsize / bsize; + + vol->extent_no = main_meta->md_all; + + vol->data_blkno = (vol->truncated_blkno - 1) * vol->extent_no; + + vol->data_offset = 0; + + if (main_meta->md_all > HR_MAX_EXTENTS) { + HR_DEBUG("Assembled volume has %u extents (max = %u)", + (unsigned)main_meta->md_all, HR_MAX_EXTENTS); + rc = EINVAL; + goto error; + } + + vol->strip_size = main_meta->md_stripesize; + + memcpy(vol->in_mem_md, main_meta, sizeof(struct g_stripe_metadata)); + + list_foreach(*list, link, struct dev_list_member, iter) { + struct g_stripe_metadata *iter_meta = iter->md; + uint16_t index = iter_meta->md_no; + + vol->extents[index].svc_id = iter->svc_id; + iter->fini = false; + + vol->extents[index].status = HR_EXT_ONLINE; + } + + for (size_t i = 0; i < vol->extent_no; i++) { + if (vol->extents[i].status == HR_EXT_NONE) + vol->extents[i].status = HR_EXT_MISSING; + } + +error: + return rc; +} + +static void meta_stripe_encode(void *md_v, void *block) +{ + HR_DEBUG("%s()", __func__); + + stripe_metadata_encode(md_v, block); +} + +static errno_t meta_stripe_decode(const void *block, void *md_v) +{ + HR_DEBUG("%s()", __func__); + + stripe_metadata_decode(block, md_v); + + return EOK; +} + +static errno_t meta_stripe_get_block(service_id_t dev, void **rblock) +{ + HR_DEBUG("%s()", __func__); + + errno_t rc; + uint64_t blkno; + size_t bsize; + void *block; + + if (rblock == NULL) + return EINVAL; + + rc = block_get_bsize(dev, &bsize); + if (rc != EOK) + return rc; + + if (bsize < sizeof(struct g_stripe_metadata)) + return EINVAL; + + rc = block_get_nblocks(dev, &blkno); + if (rc != EOK) + return rc; + + if (blkno < 1) + return EINVAL; + + block = malloc(bsize); + if (block == NULL) + return ENOMEM; + + rc = block_read_direct(dev, blkno - 1, 1, block); + /* + * XXX: here maybe call vol status event or the state callback... + * + * but need to pass vol pointer + */ + if (rc != EOK) { + free(block); + return rc; + } + + *rblock = block; + return EOK; +} + +static errno_t meta_stripe_write_block(service_id_t dev, const void *block) +{ + HR_DEBUG("%s()", __func__); + + errno_t rc; + uint64_t blkno; + size_t bsize; + + rc = block_get_bsize(dev, &bsize); + if (rc != EOK) + return rc; + + if (bsize < sizeof(struct g_stripe_metadata)) + return EINVAL; + + rc = block_get_nblocks(dev, &blkno); + if (rc != EOK) + return rc; + + if (blkno < 1) + return EINVAL; + + rc = block_write_direct(dev, blkno - 1, 1, block); + + return rc; +} + +static bool meta_stripe_has_valid_magic(const void *md_v) +{ + HR_DEBUG("%s()", __func__); + + const struct g_stripe_metadata *md = md_v; + + if (str_lcmp(md->md_magic, G_STRIPE_MAGIC, 16) != 0) + return false; + + return true; +} + +static bool meta_stripe_compare_uuids(const void *md1_v, const void *md2_v) +{ + const struct g_stripe_metadata *md1 = md1_v; + const struct g_stripe_metadata *md2 = md2_v; + if (md1->md_id == md2->md_id) + return true; + + return false; +} + +static void meta_stripe_inc_counter(void *md_v) +{ + (void)md_v; +} + +static errno_t meta_stripe_save(hr_volume_t *vol, bool with_state_callback) +{ + HR_DEBUG("%s()", __func__); + + return EOK; +} + +static const char *meta_stripe_get_devname(const void *md_v) +{ + const struct g_stripe_metadata *md = md_v; + + return md->md_name; +} + +static hr_level_t meta_stripe_get_level(const void *md_v) +{ + (void)md_v; + + return HR_LVL_0; +} + +static uint64_t meta_stripe_get_data_offset(void) +{ + return 0; +} + +static size_t meta_stripe_get_size(void) +{ + return 1; +} + +static uint8_t meta_stripe_get_flags(void) +{ + uint8_t flags = 0; + + return flags; +} + +static hr_metadata_type_t meta_stripe_get_type(void) +{ + return HR_METADATA_GEOM_STRIPE; +} + +static void meta_stripe_dump(const void *md_v) +{ + HR_DEBUG("%s()", __func__); + + const struct g_stripe_metadata *md = md_v; + + printf(" magic: %s\n", md->md_magic); + printf(" version: %u\n", (u_int)md->md_version); + printf(" name: %s\n", md->md_name); + printf(" id: %u\n", (u_int)md->md_id); + printf(" no: %u\n", (u_int)md->md_no); + printf(" all: %u\n", (u_int)md->md_all); + printf("stripesize: %u\n", (u_int)md->md_stripesize); + printf(" mediasize: %jd\n", (intmax_t)md->md_provsize); +} + +/** @} + */ diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index 60ee55933c..49fc3b43a3 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -50,14 +50,17 @@ #include "var.h" #include "metadata/foreign/geom/g_mirror.h" +#include "metadata/foreign/geom/g_stripe.h" #include "metadata/native.h" extern hr_superblock_ops_t metadata_native_ops; extern hr_superblock_ops_t metadata_gmirror_ops; +extern hr_superblock_ops_t metadata_stripe_ops; static hr_superblock_ops_t *hr_superblock_ops_all[] = { [HR_METADATA_NATIVE] = &metadata_native_ops, - [HR_METADATA_GEOM_MIRROR] = &metadata_gmirror_ops + [HR_METADATA_GEOM_MIRROR] = &metadata_gmirror_ops, + [HR_METADATA_GEOM_STRIPE] = &metadata_stripe_ops }; hr_superblock_ops_t *get_type_ops(hr_metadata_type_t type) From fb06476f08639bdd9ea2c65ef95e16644620591d Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 21 Apr 2025 15:20:05 +0200 Subject: [PATCH 192/324] hr: use enum for RAID layouts --- uspace/lib/device/include/hr.h | 23 +++++------ uspace/lib/device/src/hr.c | 40 ++++++++----------- .../srv/bd/hr/metadata/foreign/geom/mirror.c | 4 +- .../srv/bd/hr/metadata/foreign/geom/stripe.c | 2 + uspace/srv/bd/hr/metadata/native.c | 3 +- uspace/srv/bd/hr/var.h | 2 +- 6 files changed, 33 insertions(+), 41 deletions(-) diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index 8eb78cc403..44db1658e8 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -54,17 +54,14 @@ typedef enum hr_level { HR_LVL_UNKNOWN = 0xFF } hr_level_t; -/* - * SNIA - * Common RAID Disk Data Format - * Specification - * Version 2.0 Revision 19 - */ -#define HR_RLQ_RAID4_0 0x00 /* RAID-4 Non-Rotating Parity 0 */ -#define HR_RLQ_RAID4_N 0x01 /* RAID-4 Non-Rotating Parity N */ -#define HR_RLQ_RAID5_0R 0x00 /* RAID-5 Rotating Parity 0 with Data Restart */ -#define HR_RLQ_RAID5_NR 0x02 /* RAID-5 Rotating Parity N with Data Restart */ -#define HR_RLQ_RAID5_NC 0x03 /* RAID-5 Rotating Parity N with Data Continuation */ +typedef enum hr_layout { + HR_RLQ_NONE = 0, + HR_RLQ_RAID4_0, /* RAID-4 Non-Rotating Parity 0 */ + HR_RLQ_RAID4_N, /* RAID-4 Non-Rotating Parity N */ + HR_RLQ_RAID5_0R, /* RAID-5 Rotating Parity 0 with Data Restart */ + HR_RLQ_RAID5_NR, /* RAID-5 Rotating Parity N with Data Restart */ + HR_RLQ_RAID5_NC /* RAID-5 Rotating Parity N with Data Continuation */ +} hr_layout_t; typedef enum hr_vol_status { HR_VOL_NONE = 0, /* Unknown/None */ @@ -118,7 +115,7 @@ typedef enum { HR_METADATA_NATIVE = 0, HR_METADATA_GEOM_MIRROR = 1, HR_METADATA_GEOM_STRIPE = 2, - HR_METADATA_LAST_DUMMY = 3 + HR_METADATA_LAST_DUMMY } hr_metadata_type_t; extern errno_t hr_sess_init(hr_t **); @@ -131,7 +128,7 @@ extern errno_t hr_add_hotspare(service_id_t, service_id_t); extern errno_t hr_print_status(void); extern const char *hr_get_vol_status_msg(hr_vol_status_t); extern const char *hr_get_ext_status_msg(hr_ext_status_t); -extern const char *hr_get_layout_str(hr_level_t, uint8_t); +extern const char *hr_get_layout_str(hr_layout_t); extern const char *hr_get_metadata_type_str(hr_metadata_type_t); #endif diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index 8e21479b7c..218d17188b 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -206,7 +206,7 @@ static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info) printf("level: %d\n", vol_info->level); if (vol_info->level == HR_LVL_4 || vol_info->level == HR_LVL_5) { printf("layout: %s\n", - hr_get_layout_str(vol_info->level, vol_info->layout)); + hr_get_layout_str(vol_info->layout)); } if (vol_info->level == HR_LVL_0 || vol_info->level == HR_LVL_4) { if (vol_info->strip_size / 1024 < 1) @@ -427,31 +427,23 @@ const char *hr_get_ext_status_msg(hr_ext_status_t status) } } -const char *hr_get_layout_str(hr_level_t level, uint8_t layout) +const char *hr_get_layout_str(hr_layout_t layout) { - switch (level) { - case HR_LVL_4: - switch (layout) { - case HR_RLQ_RAID4_0: - return "RAID-4 Non-Rotating Parity 0"; - case HR_RLQ_RAID4_N: - return "RAID-4 Non-Rotating Parity N"; - default: - return "Invalid RAID 4 layout"; - } - case HR_LVL_5: - switch (layout) { - case HR_RLQ_RAID5_0R: - return "RAID-5 Rotating Parity 0 with Data Restart"; - case HR_RLQ_RAID5_NR: - return "RAID-5 Rotating Parity N with Data Restart"; - case HR_RLQ_RAID5_NC: - return "RAID-5 Rotating Parity N with Data Continuation"; - default: - return "Invalid RAID 5 layout"; - } + switch (layout) { + case HR_RLQ_NONE: + return "RAID layout not set"; + case HR_RLQ_RAID4_0: + return "RAID-4 Non-Rotating Parity 0"; + case HR_RLQ_RAID4_N: + return "RAID-4 Non-Rotating Parity N"; + case HR_RLQ_RAID5_0R: + return "RAID-5 Rotating Parity 0 with Data Restart"; + case HR_RLQ_RAID5_NR: + return "RAID-5 Rotating Parity N with Data Restart"; + case HR_RLQ_RAID5_NC: + return "RAID-5 Rotating Parity N with Data Continuation"; default: - return "Invalid RAID level"; + return "Invalid RAID layout"; } } diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/mirror.c b/uspace/srv/bd/hr/metadata/foreign/geom/mirror.c index 43863dc3e7..a36a6f3c2b 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/mirror.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/mirror.c @@ -141,9 +141,9 @@ static errno_t meta_gmirror_init_meta2vol(const list_t *list, hr_volume_t *vol) vol->extent_no = main_meta->md_all; - /* vol->layout = main_meta->layout; */ + vol->layout = HR_RLQ_NONE; - /* vol->strip_size = main_meta->strip_size; */ + vol->strip_size = 0; vol->bsize = main_meta->md_sectorsize; diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/stripe.c b/uspace/srv/bd/hr/metadata/foreign/geom/stripe.c index c47e69e11f..fcffb7302d 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/stripe.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/stripe.c @@ -155,6 +155,8 @@ static errno_t meta_stripe_init_meta2vol(const list_t *list, hr_volume_t *vol) vol->strip_size = main_meta->md_stripesize; + vol->layout = HR_RLQ_NONE; + memcpy(vol->in_mem_md, main_meta, sizeof(struct g_stripe_metadata)); list_foreach(*list, link, struct dev_list_member, iter) { diff --git a/uspace/srv/bd/hr/metadata/native.c b/uspace/srv/bd/hr/metadata/native.c index 6456e45a81..b03c00681a 100644 --- a/uspace/srv/bd/hr/metadata/native.c +++ b/uspace/srv/bd/hr/metadata/native.c @@ -155,10 +155,11 @@ static errno_t meta_native_init_meta2vol(const list_t *list, hr_volume_t *vol) vol->truncated_blkno = main_meta->truncated_blkno; vol->data_offset = main_meta->data_offset; vol->extent_no = main_meta->extent_no; - /* vol->level = main_meta->level; */ + /* vol->level = main_meta->level; */ /* already set */ vol->layout = main_meta->layout; vol->strip_size = main_meta->strip_size; vol->bsize = main_meta->bsize; + /* already set */ /* memcpy(vol->devname, main_meta->devname, HR_DEVNAME_LEN); */ memcpy(vol->in_mem_md, main_meta, sizeof(hr_metadata_t)); diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index 22bfca7226..2cc768f86a 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -85,7 +85,7 @@ typedef struct hr_volume { uint64_t data_offset; /* user data offset in blocks */ uint32_t strip_size; /* strip size */ hr_level_t level; /* volume level */ - uint8_t layout; /* RAID Level Qualifier */ + hr_layout_t layout; /* RAID Level Qualifier */ char devname[HR_DEVNAME_LEN]; hr_extent_t extents[HR_MAX_EXTENTS]; From c6d2af86e445afa373d0f1c485190ea8c8446732 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 21 Apr 2025 16:04:48 +0200 Subject: [PATCH 193/324] hr: hr.c: more specific message for unsupported hotspare --- uspace/srv/bd/hr/hr.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 81a6a53dc4..e5121ff724 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -327,8 +327,9 @@ static void hr_add_hotspare_srv(ipc_call_t *icall) } if (vol->hr_ops.add_hotspare == NULL) { - HR_DEBUG("hr_add_hotspare(): not supported on RAID level %d\n", - vol->level); + HR_NOTE("hotspare not supported on RAID level = %d, " + "metadata type = %s\n", vol->level, + hr_get_metadata_type_str(vol->meta_ops->get_type())); async_answer_0(icall, ENOTSUP); return; } From a05675980563c73cc5a4ce9b05fefb81f21615bb Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 21 Apr 2025 22:32:29 +0200 Subject: [PATCH 194/324] hr: hr.c: style Accepting connections. message --- uspace/srv/bd/hr/hr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index e5121ff724..51684e171d 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -497,7 +497,7 @@ int main(int argc, char **argv) return EEXIST; } - printf("%s: accepting connections\n", NAME); + printf("%s: Accepting connections.\n", NAME); task_retval(0); async_manager(); From d85ee06726105be6560a03df45777839024f9d34 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 22 Apr 2025 13:09:10 +0200 Subject: [PATCH 195/324] hr: geom g{mirror, stripe}: rename files, remove saving We cannot currently support GEOM::MIRROR metadata saving, because we would have to keep hardcoded provider names, and disk unique IDs. --- uspace/srv/bd/hr/meson.build | 4 +- .../foreign/geom/{mirror.c => hr_g_mirror.c} | 54 ++------- .../foreign/geom/{stripe.c => hr_g_stripe.c} | 114 +++++++++--------- uspace/srv/bd/hr/superblock.c | 6 +- 4 files changed, 75 insertions(+), 103 deletions(-) rename uspace/srv/bd/hr/metadata/foreign/geom/{mirror.c => hr_g_mirror.c} (89%) rename uspace/srv/bd/hr/metadata/foreign/geom/{stripe.c => hr_g_stripe.c} (66%) diff --git a/uspace/srv/bd/hr/meson.build b/uspace/srv/bd/hr/meson.build index c151abaf79..452c863c76 100644 --- a/uspace/srv/bd/hr/meson.build +++ b/uspace/srv/bd/hr/meson.build @@ -31,8 +31,8 @@ src = files( 'fge.c', 'hr.c', 'io.c', - 'metadata/foreign/geom/mirror.c', - 'metadata/foreign/geom/stripe.c', + 'metadata/foreign/geom/hr_g_mirror.c', + 'metadata/foreign/geom/hr_g_stripe.c', 'metadata/native.c', 'raid0.c', 'raid1.c', diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/mirror.c b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c similarity index 89% rename from uspace/srv/bd/hr/metadata/foreign/geom/mirror.c rename to uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c index a36a6f3c2b..ff8c5de88f 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/mirror.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c @@ -102,6 +102,7 @@ static errno_t meta_gmirror_init_vol2meta(const hr_volume_t *vol, void *md_v) { (void)vol; (void)md_v; + return ENOTSUP; } @@ -112,7 +113,7 @@ static errno_t meta_gmirror_init_meta2vol(const list_t *list, hr_volume_t *vol) errno_t rc = EOK; struct g_mirror_metadata *main_meta = NULL; - size_t max_counter_val = 0; + uint64_t max_counter_val = 0; list_foreach(*list, link, struct dev_list_member, iter) { struct g_mirror_metadata *iter_meta = iter->md; @@ -156,6 +157,7 @@ static errno_t meta_gmirror_init_meta2vol(const list_t *list, hr_volume_t *vol) vol->extents[index].svc_id = iter->svc_id; iter->fini = false; + /* for now no md_sync_offset handling for saved REBUILD */ if (iter_meta->md_genid == max_counter_val) vol->extents[index].status = HR_EXT_ONLINE; else @@ -290,54 +292,22 @@ static void meta_gmirror_inc_counter(void *md_v) md->md_genid++; } -/* - * XXX: finish this fcn documentation - * - * Returns ENOMEM else EOK - */ static errno_t meta_gmirror_save(hr_volume_t *vol, bool with_state_callback) { HR_DEBUG("%s()", __func__); - errno_t rc = EOK; - - void *md_block = calloc(1, vol->bsize); - if (md_block == NULL) - return ENOMEM; - - struct g_mirror_metadata *md = vol->in_mem_md; - - fibril_rwlock_read_lock(&vol->extents_lock); - - fibril_mutex_lock(&vol->md_lock); - - for (size_t i = 0; i < vol->extent_no; i++) { - hr_extent_t *ext = &vol->extents[i]; - - fibril_rwlock_read_lock(&vol->states_lock); - - /* TODO: special case for REBUILD */ - if (ext->status != HR_EXT_ONLINE) - continue; - - fibril_rwlock_read_unlock(&vol->states_lock); - - md->md_priority = i; - meta_gmirror_encode(md, md_block); - rc = meta_gmirror_write_block(ext->svc_id, md_block); - if (with_state_callback && rc != EOK) - vol->state_callback(vol, i, rc); - } - - fibril_mutex_unlock(&vol->md_lock); - - fibril_rwlock_read_unlock(&vol->extents_lock); + (void)vol; + (void)with_state_callback; - if (with_state_callback) - vol->hr_ops.status_event(vol); + /* + * cannot support right now, because would need to store the + * metadata for all disks, because of hardcoded provider names and + * most importantly, disk unique ids + */ - free(md_block); + /* silent */ return EOK; + /* return ENOTSUP; */ } static const char *meta_gmirror_get_devname(const void *md_v) diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/stripe.c b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c similarity index 66% rename from uspace/srv/bd/hr/metadata/foreign/geom/stripe.c rename to uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c index fcffb7302d..588073fc36 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/stripe.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c @@ -52,60 +52,60 @@ #include "g_stripe.h" -static void *meta_stripe_alloc_struct(void); -static errno_t meta_stripe_init_vol2meta(const hr_volume_t *, void *); -static errno_t meta_stripe_init_meta2vol(const list_t *, +static void *meta_gstripe_alloc_struct(void); +static errno_t meta_gstripe_init_vol2meta(const hr_volume_t *, void *); +static errno_t meta_gstripe_init_meta2vol(const list_t *, hr_volume_t *); -static void meta_stripe_encode(void *, void *); -static errno_t meta_stripe_decode(const void *, void *); -static errno_t meta_stripe_get_block(service_id_t, void **); -static errno_t meta_stripe_write_block(service_id_t, const void *); -static bool meta_stripe_has_valid_magic(const void *); -static bool meta_stripe_compare_uuids(const void *, const void *); -static void meta_stripe_inc_counter(void *); -static errno_t meta_stripe_save(hr_volume_t *, bool); -static const char *meta_stripe_get_devname(const void *); -static hr_level_t meta_stripe_get_level(const void *); -static uint64_t meta_stripe_get_data_offset(void); -static size_t meta_stripe_get_size(void); -static uint8_t meta_stripe_get_flags(void); -static hr_metadata_type_t meta_stripe_get_type(void); -static void meta_stripe_dump(const void *); - -hr_superblock_ops_t metadata_stripe_ops = { - .alloc_struct = meta_stripe_alloc_struct, - .init_vol2meta = meta_stripe_init_vol2meta, - .init_meta2vol = meta_stripe_init_meta2vol, - .encode = meta_stripe_encode, - .decode = meta_stripe_decode, - .get_block = meta_stripe_get_block, - .write_block = meta_stripe_write_block, - .has_valid_magic = meta_stripe_has_valid_magic, - .compare_uuids = meta_stripe_compare_uuids, - .inc_counter = meta_stripe_inc_counter, - .save = meta_stripe_save, - .get_devname = meta_stripe_get_devname, - .get_level = meta_stripe_get_level, - .get_data_offset = meta_stripe_get_data_offset, - .get_size = meta_stripe_get_size, - .get_flags = meta_stripe_get_flags, - .get_type = meta_stripe_get_type, - .dump = meta_stripe_dump +static void meta_gstripe_encode(void *, void *); +static errno_t meta_gstripe_decode(const void *, void *); +static errno_t meta_gstripe_get_block(service_id_t, void **); +static errno_t meta_gstripe_write_block(service_id_t, const void *); +static bool meta_gstripe_has_valid_magic(const void *); +static bool meta_gstripe_compare_uuids(const void *, const void *); +static void meta_gstripe_inc_counter(void *); +static errno_t meta_gstripe_save(hr_volume_t *, bool); +static const char *meta_gstripe_get_devname(const void *); +static hr_level_t meta_gstripe_get_level(const void *); +static uint64_t meta_gstripe_get_data_offset(void); +static size_t meta_gstripe_get_size(void); +static uint8_t meta_gstripe_get_flags(void); +static hr_metadata_type_t meta_gstripe_get_type(void); +static void meta_gstripe_dump(const void *); + +hr_superblock_ops_t metadata_gstripe_ops = { + .alloc_struct = meta_gstripe_alloc_struct, + .init_vol2meta = meta_gstripe_init_vol2meta, + .init_meta2vol = meta_gstripe_init_meta2vol, + .encode = meta_gstripe_encode, + .decode = meta_gstripe_decode, + .get_block = meta_gstripe_get_block, + .write_block = meta_gstripe_write_block, + .has_valid_magic = meta_gstripe_has_valid_magic, + .compare_uuids = meta_gstripe_compare_uuids, + .inc_counter = meta_gstripe_inc_counter, + .save = meta_gstripe_save, + .get_devname = meta_gstripe_get_devname, + .get_level = meta_gstripe_get_level, + .get_data_offset = meta_gstripe_get_data_offset, + .get_size = meta_gstripe_get_size, + .get_flags = meta_gstripe_get_flags, + .get_type = meta_gstripe_get_type, + .dump = meta_gstripe_dump }; -static void *meta_stripe_alloc_struct(void) +static void *meta_gstripe_alloc_struct(void) { return calloc(1, sizeof(struct g_stripe_metadata)); } -static errno_t meta_stripe_init_vol2meta(const hr_volume_t *vol, void *md_v) +static errno_t meta_gstripe_init_vol2meta(const hr_volume_t *vol, void *md_v) { (void)vol; (void)md_v; return ENOTSUP; } -static errno_t meta_stripe_init_meta2vol(const list_t *list, hr_volume_t *vol) +static errno_t meta_gstripe_init_meta2vol(const list_t *list, hr_volume_t *vol) { HR_DEBUG("%s()", __func__); @@ -127,7 +127,7 @@ static errno_t meta_stripe_init_meta2vol(const list_t *list, hr_volume_t *vol) list_foreach(*list, link, struct dev_list_member, iter) { struct g_stripe_metadata *iter_meta = iter->md; - meta_stripe_dump(iter_meta); + meta_gstripe_dump(iter_meta); if (iter_meta->md_provsize < smallest_provider_size) { smallest_provider_size = iter_meta->md_provsize; @@ -178,14 +178,14 @@ static errno_t meta_stripe_init_meta2vol(const list_t *list, hr_volume_t *vol) return rc; } -static void meta_stripe_encode(void *md_v, void *block) +static void meta_gstripe_encode(void *md_v, void *block) { HR_DEBUG("%s()", __func__); stripe_metadata_encode(md_v, block); } -static errno_t meta_stripe_decode(const void *block, void *md_v) +static errno_t meta_gstripe_decode(const void *block, void *md_v) { HR_DEBUG("%s()", __func__); @@ -194,7 +194,7 @@ static errno_t meta_stripe_decode(const void *block, void *md_v) return EOK; } -static errno_t meta_stripe_get_block(service_id_t dev, void **rblock) +static errno_t meta_gstripe_get_block(service_id_t dev, void **rblock) { HR_DEBUG("%s()", __func__); @@ -239,7 +239,7 @@ static errno_t meta_stripe_get_block(service_id_t dev, void **rblock) return EOK; } -static errno_t meta_stripe_write_block(service_id_t dev, const void *block) +static errno_t meta_gstripe_write_block(service_id_t dev, const void *block) { HR_DEBUG("%s()", __func__); @@ -266,7 +266,7 @@ static errno_t meta_stripe_write_block(service_id_t dev, const void *block) return rc; } -static bool meta_stripe_has_valid_magic(const void *md_v) +static bool meta_gstripe_has_valid_magic(const void *md_v) { HR_DEBUG("%s()", __func__); @@ -278,7 +278,7 @@ static bool meta_stripe_has_valid_magic(const void *md_v) return true; } -static bool meta_stripe_compare_uuids(const void *md1_v, const void *md2_v) +static bool meta_gstripe_compare_uuids(const void *md1_v, const void *md2_v) { const struct g_stripe_metadata *md1 = md1_v; const struct g_stripe_metadata *md2 = md2_v; @@ -288,55 +288,55 @@ static bool meta_stripe_compare_uuids(const void *md1_v, const void *md2_v) return false; } -static void meta_stripe_inc_counter(void *md_v) +static void meta_gstripe_inc_counter(void *md_v) { (void)md_v; } -static errno_t meta_stripe_save(hr_volume_t *vol, bool with_state_callback) +static errno_t meta_gstripe_save(hr_volume_t *vol, bool with_state_callback) { HR_DEBUG("%s()", __func__); return EOK; } -static const char *meta_stripe_get_devname(const void *md_v) +static const char *meta_gstripe_get_devname(const void *md_v) { const struct g_stripe_metadata *md = md_v; return md->md_name; } -static hr_level_t meta_stripe_get_level(const void *md_v) +static hr_level_t meta_gstripe_get_level(const void *md_v) { (void)md_v; return HR_LVL_0; } -static uint64_t meta_stripe_get_data_offset(void) +static uint64_t meta_gstripe_get_data_offset(void) { return 0; } -static size_t meta_stripe_get_size(void) +static size_t meta_gstripe_get_size(void) { return 1; } -static uint8_t meta_stripe_get_flags(void) +static uint8_t meta_gstripe_get_flags(void) { uint8_t flags = 0; return flags; } -static hr_metadata_type_t meta_stripe_get_type(void) +static hr_metadata_type_t meta_gstripe_get_type(void) { return HR_METADATA_GEOM_STRIPE; } -static void meta_stripe_dump(const void *md_v) +static void meta_gstripe_dump(const void *md_v) { HR_DEBUG("%s()", __func__); diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index 49fc3b43a3..c5d8bcc50a 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -51,16 +51,18 @@ #include "metadata/foreign/geom/g_mirror.h" #include "metadata/foreign/geom/g_stripe.h" +#include "metadata/foreign/softraid/softraidvar.h" + #include "metadata/native.h" extern hr_superblock_ops_t metadata_native_ops; extern hr_superblock_ops_t metadata_gmirror_ops; -extern hr_superblock_ops_t metadata_stripe_ops; +extern hr_superblock_ops_t metadata_gstripe_ops; static hr_superblock_ops_t *hr_superblock_ops_all[] = { [HR_METADATA_NATIVE] = &metadata_native_ops, [HR_METADATA_GEOM_MIRROR] = &metadata_gmirror_ops, - [HR_METADATA_GEOM_STRIPE] = &metadata_stripe_ops + [HR_METADATA_GEOM_STRIPE] = &metadata_gstripe_ops }; hr_superblock_ops_t *get_type_ops(hr_metadata_type_t type) From dd76b4648f7d81cb8dd1a5f69452fc37119dbb4f Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Wed, 23 Apr 2025 00:39:09 +0200 Subject: [PATCH 196/324] hr: metadata/native.c: use uint64_t for counter --- uspace/srv/bd/hr/metadata/native.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uspace/srv/bd/hr/metadata/native.c b/uspace/srv/bd/hr/metadata/native.c index b03c00681a..810bcd95c8 100644 --- a/uspace/srv/bd/hr/metadata/native.c +++ b/uspace/srv/bd/hr/metadata/native.c @@ -139,7 +139,7 @@ static errno_t meta_native_init_meta2vol(const list_t *list, hr_volume_t *vol) HR_DEBUG("%s()", __func__); hr_metadata_t *main_meta = NULL; - size_t max_counter_val = 0; + uint64_t max_counter_val = 0; list_foreach(*list, link, struct dev_list_member, iter) { hr_metadata_t *iter_meta = (hr_metadata_t *)iter->md; From af1b25df666ebb21b19da8ecc5c91dd5458fe76f Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Wed, 23 Apr 2025 00:42:19 +0200 Subject: [PATCH 197/324] hr: metadata/geom/g_mirror.h: fix checksums --- uspace/srv/bd/hr/metadata/foreign/geom/g_mirror.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/g_mirror.h b/uspace/srv/bd/hr/metadata/foreign/geom/g_mirror.h index b9667fb839..d6a4397300 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/g_mirror.h +++ b/uspace/srv/bd/hr/metadata/foreign/geom/g_mirror.h @@ -132,7 +132,7 @@ mirror_metadata_encode(struct g_mirror_metadata *md, u_char *data) errno_t rc = create_hash(data, 119, md5_hash, HASH_MD5); assert(rc == EOK); - bcopy(md->md_hash, data + 119, 16); + bcopy(md5_hash, data + 119, 16); } static __inline int @@ -160,8 +160,7 @@ mirror_metadata_decode_v3v4(const u_char *data, struct g_mirror_metadata *md) errno_t rc = create_hash(data, 119, md5_hash, HASH_MD5); assert(rc == EOK); - memcpy(md->md_hash, data + 119, 16); - if (memcmp(md->md_hash, data + 119, 16) != 0) + if (memcmp(md->md_hash, md5_hash, 16) != 0) return (EINVAL); return (0); From a261634f655aa85f7826250af1d0986540061fbc Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Wed, 23 Apr 2025 12:43:28 +0200 Subject: [PATCH 198/324] hr: OpenBSD softraid metadata support --- uspace/srv/bd/hr/meson.build | 2 + .../metadata/foreign/softraid/hr_softraid.c | 495 ++++++++++++++++++ .../hr/metadata/foreign/softraid/softraid.c | 126 +++++ .../metadata/foreign/softraid/softraidvar.h | 144 +++++ uspace/srv/bd/hr/superblock.c | 4 +- 5 files changed, 770 insertions(+), 1 deletion(-) create mode 100644 uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c create mode 100644 uspace/srv/bd/hr/metadata/foreign/softraid/softraid.c create mode 100644 uspace/srv/bd/hr/metadata/foreign/softraid/softraidvar.h diff --git a/uspace/srv/bd/hr/meson.build b/uspace/srv/bd/hr/meson.build index 452c863c76..c96a77d9e6 100644 --- a/uspace/srv/bd/hr/meson.build +++ b/uspace/srv/bd/hr/meson.build @@ -33,6 +33,8 @@ src = files( 'io.c', 'metadata/foreign/geom/hr_g_mirror.c', 'metadata/foreign/geom/hr_g_stripe.c', + 'metadata/foreign/softraid/hr_softraid.c', + 'metadata/foreign/softraid/softraid.c', 'metadata/native.c', 'raid0.c', 'raid1.c', diff --git a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c new file mode 100644 index 0000000000..83312b4295 --- /dev/null +++ b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c @@ -0,0 +1,495 @@ +/* + * 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 +#include +#include +#include +#include + +#include "../../../util.h" +#include "../../../var.h" + +#include "softraidvar.h" + +static void *meta_softraid_alloc_struct(void); +static errno_t meta_softraid_init_vol2meta(const hr_volume_t *, + void *); +static errno_t meta_softraid_init_meta2vol(const list_t *, + hr_volume_t *); +static void meta_softraid_encode(void *, void *); +static errno_t meta_softraid_decode(const void *, void *); +static errno_t meta_softraid_get_block(service_id_t, void **); +static errno_t meta_softraid_write_block(service_id_t, const void *); +static bool meta_softraid_has_valid_magic(const void *); +static bool meta_softraid_compare_uuids(const void *, + const void *); +static void meta_softraid_inc_counter(void *); +static errno_t meta_softraid_save(hr_volume_t *, bool); +static const char *meta_softraid_get_devname(const void *); +static hr_level_t meta_softraid_get_level(const void *); +static uint64_t meta_softraid_get_data_offset(void); +static size_t meta_softraid_get_size(void); +static uint8_t meta_softraid_get_flags(void); +static hr_metadata_type_t meta_softraid_get_type(void); +static void meta_softraid_dump(const void *); + +hr_superblock_ops_t metadata_softraid_ops = { + .alloc_struct = meta_softraid_alloc_struct, + .init_vol2meta = meta_softraid_init_vol2meta, + .init_meta2vol = meta_softraid_init_meta2vol, + .encode = meta_softraid_encode, + .decode = meta_softraid_decode, + .get_block = meta_softraid_get_block, + .write_block = meta_softraid_write_block, + .has_valid_magic = meta_softraid_has_valid_magic, + .compare_uuids = meta_softraid_compare_uuids, + .inc_counter = meta_softraid_inc_counter, + .save = meta_softraid_save, + .get_devname = meta_softraid_get_devname, + .get_level = meta_softraid_get_level, + .get_data_offset = meta_softraid_get_data_offset, + .get_size = meta_softraid_get_size, + .get_flags = meta_softraid_get_flags, + .get_type = meta_softraid_get_type, + .dump = meta_softraid_dump +}; + +static void *meta_softraid_alloc_struct(void) +{ + return calloc(1, SR_META_SIZE * DEV_BSIZE); +} + +static errno_t meta_softraid_init_vol2meta(const hr_volume_t *vol, void *md_v) +{ + (void)vol; + (void)md_v; + return ENOTSUP; +} + +static errno_t meta_softraid_init_meta2vol(const list_t *list, hr_volume_t *vol) +{ + HR_DEBUG("%s()", __func__); + + errno_t rc = EOK; + + struct sr_metadata *main_meta = NULL; + uint64_t max_counter_val = 0; + + list_foreach(*list, link, struct dev_list_member, iter) { + struct sr_metadata *iter_meta = iter->md; + + if (iter_meta->ssd_ondisk >= max_counter_val) { + max_counter_val = iter_meta->ssd_ondisk; + main_meta = iter_meta; + } + } + + assert(main_meta != NULL); + + vol->bsize = main_meta->ssdi.ssd_secsize; + + vol->data_blkno = main_meta->ssdi.ssd_size; + + /* get coerced size from some (first) chunk metadata */ + struct sr_meta_chunk *mc = (struct sr_meta_chunk *)(main_meta + 1); + vol->truncated_blkno = mc->scmi.scm_coerced_size; + + vol->data_offset = main_meta->ssd_data_blkno; + + if (main_meta->ssdi.ssd_chunk_no > HR_MAX_EXTENTS) { + HR_DEBUG("Assembled volume has %u extents (max = %u)", + (unsigned)main_meta->ssdi.ssd_chunk_no, + HR_MAX_EXTENTS); + rc = EINVAL; + goto error; + } + + vol->extent_no = main_meta->ssdi.ssd_chunk_no; + + if (main_meta->ssdi.ssd_level == 5) + vol->layout = HR_RLQ_RAID5_NR; + else + vol->layout = HR_RLQ_NONE; + + vol->strip_size = main_meta->ssdi.ssd_strip_size; + + memcpy(vol->in_mem_md, main_meta, SR_META_SIZE * DEV_BSIZE); + + list_foreach(*list, link, struct dev_list_member, iter) { + struct sr_metadata *iter_meta = iter->md; + + uint8_t index = iter_meta->ssdi.ssd_chunk_id; + + vol->extents[index].svc_id = iter->svc_id; + iter->fini = false; + + /* for now no ssd_rebuild handling for saved REBUILD */ + if (iter_meta->ssd_ondisk == max_counter_val) + vol->extents[index].status = HR_EXT_ONLINE; + else + vol->extents[index].status = HR_EXT_INVALID; + + index++; + } + + for (size_t i = 0; i < vol->extent_no; i++) { + if (vol->extents[i].status == HR_EXT_NONE) + vol->extents[i].status = HR_EXT_MISSING; + } + +error: + return rc; +} + +static void meta_softraid_encode(void *md_v, void *block) +{ + HR_DEBUG("%s()", __func__); + + (void)md_v; + (void)block; +} + +static errno_t meta_softraid_decode(const void *block, void *md_v) +{ + HR_DEBUG("%s()", __func__); + + errno_t rc = EOK; + struct sr_metadata *md = md_v; + uint8_t md5_hash[16]; + + struct sr_metadata *scratch_md = meta_softraid_alloc_struct(); + if (scratch_md == NULL) + return ENOMEM; + + memcpy(scratch_md, block, meta_softraid_get_size() * 512); + + md->ssdi.ssd_magic = + uint64_t_le2host(scratch_md->ssdi.ssd_magic); + if (md->ssdi.ssd_magic != SR_MAGIC) { + rc = EINVAL; + goto error; + } + md->ssdi.ssd_version = uint32_t_le2host(scratch_md->ssdi.ssd_version); + if (md->ssdi.ssd_version != SR_META_VERSION) { + HR_DEBUG("unsupported metadata version\n"); + rc = EINVAL; + goto error; + } + md->ssdi.ssd_vol_flags = + uint32_t_le2host(scratch_md->ssdi.ssd_vol_flags); + memcpy(&md->ssdi.ssd_uuid, &scratch_md->ssdi.ssd_uuid, SR_UUID_MAX); + + md->ssdi.ssd_chunk_no = + uint32_t_le2host(scratch_md->ssdi.ssd_chunk_no); + md->ssdi.ssd_chunk_id = + uint32_t_le2host(scratch_md->ssdi.ssd_chunk_id); + + md->ssdi.ssd_opt_no = uint32_t_le2host(scratch_md->ssdi.ssd_opt_no); + if (md->ssdi.ssd_opt_no > 0) { + HR_DEBUG("unsupported optional metadata\n"); + rc = EINVAL; + goto error; + } + md->ssdi.ssd_secsize = uint32_t_le2host(scratch_md->ssdi.ssd_secsize); + if (md->ssdi.ssd_secsize != DEV_BSIZE) { + HR_DEBUG("unsupported sector size\n"); + rc = EINVAL; + goto error; + } + + md->ssdi.ssd_volid = uint32_t_le2host(scratch_md->ssdi.ssd_volid); + md->ssdi.ssd_level = uint32_t_le2host(scratch_md->ssdi.ssd_level); + md->ssdi.ssd_size = int64_t_le2host(scratch_md->ssdi.ssd_size); + memcpy(md->ssdi.ssd_vendor, scratch_md->ssdi.ssd_vendor, 8); + memcpy(md->ssdi.ssd_product, scratch_md->ssdi.ssd_product, 16); + memcpy(md->ssdi.ssd_revision, scratch_md->ssdi.ssd_revision, 4); + md->ssdi.ssd_strip_size = + uint32_t_le2host(scratch_md->ssdi.ssd_strip_size); + + memcpy(md->ssd_checksum, scratch_md->ssd_checksum, MD5_DIGEST_LENGTH); + rc = create_hash((const uint8_t *)&md->ssdi, + sizeof(struct sr_meta_invariant), md5_hash, HASH_MD5); + assert(rc == EOK); + if (memcmp(md5_hash, md->ssd_checksum, 16) != 0) { + HR_DEBUG("ssd_checksum invalid\n"); + rc = EINVAL; + goto error; + } + + memcpy(md->ssd_devname, scratch_md->ssd_devname, 32); + md->ssd_meta_flags = uint32_t_le2host(scratch_md->ssd_meta_flags); + md->ssd_data_blkno = uint32_t_le2host(scratch_md->ssd_data_blkno); + md->ssd_ondisk = uint64_t_le2host(scratch_md->ssd_ondisk); + md->ssd_rebuild = int64_t_le2host(scratch_md->ssd_rebuild); + + struct sr_meta_chunk *scratch_mc = + (struct sr_meta_chunk *)(scratch_md + 1); + struct sr_meta_chunk *mc = (struct sr_meta_chunk *)(md + 1); + for (size_t i = 0; i < md->ssdi.ssd_chunk_no; i++, mc++, scratch_mc++) { + mc->scmi.scm_volid = + uint32_t_le2host(scratch_mc->scmi.scm_volid); + mc->scmi.scm_chunk_id = + uint32_t_le2host(scratch_mc->scmi.scm_chunk_id); + memcpy(mc->scmi.scm_devname, scratch_mc->scmi.scm_devname, 32); + mc->scmi.scm_size = int64_t_le2host(scratch_mc->scmi.scm_size); + mc->scmi.scm_coerced_size = + int64_t_le2host(scratch_mc->scmi.scm_coerced_size); + memcpy(&mc->scmi.scm_uuid, &scratch_mc->scmi.scm_uuid, + SR_UUID_MAX); + + memcpy(mc->scm_checksum, scratch_mc->scm_checksum, + MD5_DIGEST_LENGTH); + mc->scm_status = uint32_t_le2host(scratch_mc->scm_status); + + /* + * This commented piece of code found a bug in + * OpenBSD softraid chunk metadata initialization, + * fix has been proposed [1], if it is fixed, feel free + * to uncomment, although it will work only on new + * volumes. + * + * [1]: https://marc.info/?l=openbsd-tech&m=174535579711235&w=2 + */ + /* + * rc = create_hash((const uint8_t *)&mc->scmi, + * sizeof(struct sr_meta_chunk_invariant), md5_hash, HASH_MD5); + * assert(rc == EOK); + * if (memcmp(md5_hash, mc->scm_checksum, 16) != 0) { + * HR_DEBUG("chunk %zu, scm_checksum invalid\n", i); + * rc = EINVAL; + * goto error; + * } + */ + } + + struct sr_meta_opt_hdr *scratch_om = + (struct sr_meta_opt_hdr *)((u_int8_t *)(scratch_md + 1) + + sizeof(struct sr_meta_chunk) * md->ssdi.ssd_chunk_no); + struct sr_meta_opt_hdr *om = + (struct sr_meta_opt_hdr *)((u_int8_t *)(md + 1) + + sizeof(struct sr_meta_chunk) * md->ssdi.ssd_chunk_no); + for (size_t i = 0; i < md->ssdi.ssd_opt_no; i++) { + om->som_type = uint32_t_le2host(scratch_om->som_type); + om->som_length = uint32_t_le2host(scratch_om->som_length); + memcpy(om->som_checksum, scratch_om->som_checksum, + MD5_DIGEST_LENGTH); + + /* + * No need to do checksum, we don't support optional headers. + * Despite this, still load it the headers. + */ + + om = (struct sr_meta_opt_hdr *)((void *)om + + om->som_length); + scratch_om = (struct sr_meta_opt_hdr *)((void *)scratch_om + + om->som_length); + } + +error: + free(scratch_md); + + return rc; +} + +static errno_t meta_softraid_get_block(service_id_t dev, void **rblock) +{ + HR_DEBUG("%s()", __func__); + + errno_t rc; + uint64_t blkno; + size_t bsize; + void *block; + + if (rblock == NULL) + return EINVAL; + + rc = block_get_bsize(dev, &bsize); + if (rc != EOK) + return rc; + + if (bsize != DEV_BSIZE) + return EINVAL; + + rc = block_get_nblocks(dev, &blkno); + if (rc != EOK) + return rc; + + if (blkno < SR_META_OFFSET + SR_META_SIZE) + return EINVAL; + + block = malloc(bsize * SR_META_SIZE); + if (block == NULL) + return ENOMEM; + + rc = block_read_direct(dev, SR_META_OFFSET, SR_META_SIZE, block); + if (rc != EOK) { + free(block); + return rc; + } + + *rblock = block; + return EOK; +} + +static errno_t meta_softraid_write_block(service_id_t dev, const void *block) +{ + HR_DEBUG("%s()", __func__); + + errno_t rc; + uint64_t blkno; + size_t bsize; + + rc = block_get_bsize(dev, &bsize); + if (rc != EOK) + return rc; + + if (bsize != 512) + return EINVAL; + + rc = block_get_nblocks(dev, &blkno); + if (rc != EOK) + return rc; + + if (blkno < SR_META_OFFSET + SR_META_SIZE) + return EINVAL; + + rc = block_write_direct(dev, SR_META_OFFSET, SR_META_SIZE, block); + + return rc; +} + +static bool meta_softraid_has_valid_magic(const void *md_v) +{ + HR_DEBUG("%s()", __func__); + + const struct sr_metadata *md = md_v; + + if (md->ssdi.ssd_magic != SR_MAGIC) + return false; + + return true; +} + +static bool meta_softraid_compare_uuids(const void *m1_v, const void *m2_v) +{ + const struct sr_metadata *m1 = m1_v; + const struct sr_metadata *m2 = m2_v; + if (memcmp(&m1->ssdi.ssd_uuid, &m2->ssdi.ssd_uuid, + SR_UUID_MAX) == 0) + return true; + + return false; +} + +static void meta_softraid_inc_counter(void *md_v) +{ + struct sr_metadata *md = md_v; + + md->ssd_ondisk++; +} + +static errno_t meta_softraid_save(hr_volume_t *vol, bool with_state_callback) +{ + HR_DEBUG("%s()", __func__); + + /* silent */ + return EOK; +} + +static const char *meta_softraid_get_devname(const void *md_v) +{ + const struct sr_metadata *md = md_v; + + return md->ssd_devname; +} + +static hr_level_t meta_softraid_get_level(const void *md_v) +{ + const struct sr_metadata *md = md_v; + + switch (md->ssdi.ssd_level) { + case 0: + return HR_LVL_0; + case 1: + return HR_LVL_1; + case 5: + return HR_LVL_5; + default: + return HR_LVL_UNKNOWN; + } +} + +static uint64_t meta_softraid_get_data_offset(void) +{ + return SR_DATA_OFFSET; +} + +static size_t meta_softraid_get_size(void) +{ + return SR_META_SIZE; +} + +static uint8_t meta_softraid_get_flags(void) +{ + uint8_t flags = 0; + + return flags; +} + +static hr_metadata_type_t meta_softraid_get_type(void) +{ + return HR_METADATA_SOFTRAID; +} + +static void meta_softraid_dump(const void *md_v) +{ + HR_DEBUG("%s()", __func__); + + const struct sr_metadata *md = md_v; + + sr_meta_print(md); +} + +/** @} + */ diff --git a/uspace/srv/bd/hr/metadata/foreign/softraid/softraid.c b/uspace/srv/bd/hr/metadata/foreign/softraid/softraid.c new file mode 100644 index 0000000000..d501dfbe87 --- /dev/null +++ b/uspace/srv/bd/hr/metadata/foreign/softraid/softraid.c @@ -0,0 +1,126 @@ +/* $OpenBSD: softraid.c,v 1.429 2022/12/21 09:54:23 kn Exp $ */ +/* + * Copyright (c) 2007, 2008, 2009 Marco Peereboom + * Copyright (c) 2008 Chris Kuethe + * Copyright (c) 2009 Joel Sing + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* stripped down softraid.c */ + +#include +#include + +#include "softraidvar.h" + +void +sr_checksum_print(const u_int8_t *md5) +{ + int i; + + for (i = 0; i < MD5_DIGEST_LENGTH; i++) + printf("%02x", md5[i]); +} + +char * +sr_uuid_format(const struct sr_uuid *uuid) +{ + char *uuidstr; + + /* changed to match HelenOS malloc() */ + uuidstr = malloc(37); + if (uuidstr == NULL) + return NULL; + + snprintf(uuidstr, 37, + "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-" + "%02x%02x%02x%02x%02x%02x", + uuid->sui_id[0], uuid->sui_id[1], + uuid->sui_id[2], uuid->sui_id[3], + uuid->sui_id[4], uuid->sui_id[5], + uuid->sui_id[6], uuid->sui_id[7], + uuid->sui_id[8], uuid->sui_id[9], + uuid->sui_id[10], uuid->sui_id[11], + uuid->sui_id[12], uuid->sui_id[13], + uuid->sui_id[14], uuid->sui_id[15]); + + return uuidstr; +} + +void +sr_uuid_print(const struct sr_uuid *uuid, int cr) +{ + char *uuidstr; + + uuidstr = sr_uuid_format(uuid); + printf("%s%s", uuidstr, (cr ? "\n" : "")); + free(uuidstr); +} + +void +sr_meta_print(const struct sr_metadata *m) +{ + unsigned i; + struct sr_meta_chunk *mc; + struct sr_meta_opt_hdr *omh; + + /* TODO XXX: use PRI for portability */ + printf("\tssd_magic 0x%lx\n", m->ssdi.ssd_magic); + printf("\tssd_version %d\n", m->ssdi.ssd_version); + printf("\tssd_vol_flags 0x%x\n", m->ssdi.ssd_vol_flags); + printf("\tssd_uuid "); + sr_uuid_print(&m->ssdi.ssd_uuid, 1); + printf("\tssd_chunk_no %d\n", m->ssdi.ssd_chunk_no); + printf("\tssd_chunk_id %d\n", m->ssdi.ssd_chunk_id); + printf("\tssd_opt_no %d\n", m->ssdi.ssd_opt_no); + printf("\tssd_volid %d\n", m->ssdi.ssd_volid); + printf("\tssd_level %d\n", m->ssdi.ssd_level); + printf("\tssd_size %ld\n", m->ssdi.ssd_size); + printf("\tssd_devname %s\n", m->ssd_devname); + printf("\tssd_vendor %s\n", m->ssdi.ssd_vendor); + printf("\tssd_product %s\n", m->ssdi.ssd_product); + printf("\tssd_revision %s\n", m->ssdi.ssd_revision); + printf("\tssd_strip_size %d\n", m->ssdi.ssd_strip_size); + printf("\tssd_checksum "); + sr_checksum_print(m->ssd_checksum); + printf("\n"); + printf("\tssd_meta_flags 0x%x\n", m->ssd_meta_flags); + printf("\tssd_ondisk %lu\n", m->ssd_ondisk); + + mc = (struct sr_meta_chunk *)(m + 1); + for (i = 0; i < m->ssdi.ssd_chunk_no; i++, mc++) { + printf("\t\tscm_volid %d\n", mc->scmi.scm_volid); + printf("\t\tscm_chunk_id %d\n", mc->scmi.scm_chunk_id); + printf("\t\tscm_devname %s\n", mc->scmi.scm_devname); + printf("\t\tscm_size %ld\n", mc->scmi.scm_size); + printf("\t\tscm_coerced_size %ld\n", mc->scmi.scm_coerced_size); + printf("\t\tscm_uuid "); + sr_uuid_print(&mc->scmi.scm_uuid, 1); + printf("\t\tscm_checksum "); + sr_checksum_print(mc->scm_checksum); + printf("\n"); + printf("\t\tscm_status %d\n", mc->scm_status); + } + + omh = (struct sr_meta_opt_hdr *)((u_int8_t *)(m + 1) + + sizeof(struct sr_meta_chunk) * m->ssdi.ssd_chunk_no); + for (i = 0; i < m->ssdi.ssd_opt_no; i++) { + printf("\t\t\tsom_type %d\n", omh->som_type); + printf("\t\t\tsom_checksum "); + sr_checksum_print(omh->som_checksum); + printf("\n"); + omh = (struct sr_meta_opt_hdr *)((void *)omh + + omh->som_length); + } +} diff --git a/uspace/srv/bd/hr/metadata/foreign/softraid/softraidvar.h b/uspace/srv/bd/hr/metadata/foreign/softraid/softraidvar.h new file mode 100644 index 0000000000..0c05014a43 --- /dev/null +++ b/uspace/srv/bd/hr/metadata/foreign/softraid/softraidvar.h @@ -0,0 +1,144 @@ +/* $OpenBSD: softraidvar.h,v 1.176 2022/12/19 15:27:06 kn Exp $ */ +/* + * Copyright (c) 2006 Marco Peereboom + * Copyright (c) 2008 Chris Kuethe + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** @addtogroup hr + * @{ + */ +/** + * @file + */ + +#ifndef _HR_METADATA_FOREIGN_SOFTRAID_H +#define _HR_METADATA_FOREIGN_SOFTRAID_H + +/* HelenOS specific includes, retypes */ + +#include + +typedef uint8_t u_int8_t; +typedef uint16_t u_int16_t; +typedef uint32_t u_int32_t; +typedef uint64_t u_int64_t; + +/* copied from */ +#define _DEV_BSHIFT 9 /* log2(DEV_BSIZE) */ +#define DEV_BSIZE (1 << _DEV_BSHIFT) + +/* here continues stripped down and slightly modified softraidvat.h */ + +#define MD5_DIGEST_LENGTH 16 + +#define SR_META_VERSION 6 /* bump when sr_metadata changes */ +#define SR_META_SIZE 64 /* save space at chunk beginning */ +#define SR_META_OFFSET 16 /* skip 8192 bytes at chunk beginning */ + +#define SR_BOOT_OFFSET (SR_META_OFFSET + SR_META_SIZE) +#define SR_BOOT_LOADER_SIZE 320 /* Size of boot loader storage. */ +#define SR_BOOT_LOADER_OFFSET SR_BOOT_OFFSET +#define SR_BOOT_BLOCKS_SIZE 128 /* Size of boot block storage. */ +#define SR_BOOT_BLOCKS_OFFSET (SR_BOOT_LOADER_OFFSET + SR_BOOT_LOADER_SIZE) +#define SR_BOOT_SIZE (SR_BOOT_LOADER_SIZE + SR_BOOT_BLOCKS_SIZE) + +#define SR_HEADER_SIZE (SR_META_SIZE + SR_BOOT_SIZE) +#define SR_DATA_OFFSET (SR_META_OFFSET + SR_HEADER_SIZE) + +#define SR_UUID_MAX 16 +struct sr_uuid { + u_int8_t sui_id[SR_UUID_MAX]; +} __attribute__((packed)); + +struct sr_metadata { + struct sr_meta_invariant { + /* do not change order of ssd_magic, ssd_version */ + u_int64_t ssd_magic; /* magic id */ +#define SR_MAGIC 0x4d4152436372616dLLU + u_int32_t ssd_version; /* meta data version */ + u_int32_t ssd_vol_flags; /* volume specific flags. */ + struct sr_uuid ssd_uuid; /* unique identifier */ + + /* chunks */ + u_int32_t ssd_chunk_no; /* number of chunks */ + u_int32_t ssd_chunk_id; /* chunk identifier */ + + /* optional */ + u_int32_t ssd_opt_no; /* nr of optional md elements */ + u_int32_t ssd_secsize; + + /* volume metadata */ + u_int32_t ssd_volid; /* volume id */ + u_int32_t ssd_level; /* raid level */ + int64_t ssd_size; /* virt disk size in blocks */ + char ssd_vendor[8]; /* scsi vendor */ + char ssd_product[16];/* scsi product */ + char ssd_revision[4];/* scsi revision */ + /* optional volume members */ + u_int32_t ssd_strip_size; /* strip size */ + } _sdd_invariant; +#define ssdi _sdd_invariant + /* MD5 of invariant metadata */ + u_int8_t ssd_checksum[MD5_DIGEST_LENGTH]; + char ssd_devname[32];/* /dev/XXXXX */ + u_int32_t ssd_meta_flags; +#define SR_META_DIRTY 0x1 + u_int32_t ssd_data_blkno; + u_int64_t ssd_ondisk; /* on disk version counter */ + int64_t ssd_rebuild; /* last block of rebuild */ +} __attribute__((packed)); + +struct sr_meta_chunk { + struct sr_meta_chunk_invariant { + u_int32_t scm_volid; /* vd we belong to */ + u_int32_t scm_chunk_id; /* chunk id */ + char scm_devname[32];/* /dev/XXXXX */ + int64_t scm_size; /* size of partition in blocks */ + int64_t scm_coerced_size; /* coerced sz of part in blk */ + struct sr_uuid scm_uuid; /* unique identifier */ + } _scm_invariant; +#define scmi _scm_invariant + /* MD5 of invariant chunk metadata */ + u_int8_t scm_checksum[MD5_DIGEST_LENGTH]; + u_int32_t scm_status; /* use bio bioc_disk status */ +} __attribute__((packed)); + +struct sr_meta_opt_hdr { + u_int32_t som_type; /* optional metadata type. */ + u_int32_t som_length; /* optional metadata length. */ + u_int8_t som_checksum[MD5_DIGEST_LENGTH]; +} __attribute__((packed)); + +#define SR_MD_RAID0 0 +#define SR_MD_RAID1 1 +#define SR_MD_RAID5 2 +#define SR_MD_CACHE 3 +#define SR_MD_CRYPTO 4 +/* AOE was 5 and 6. */ +/* SR_MD_RAID4 was 7. */ +#define SR_MD_RAID6 8 +#define SR_MD_CONCAT 9 +#define SR_MD_RAID1C 10 + +/* functions to export from softraid.c to hr_softraid.c */ +void sr_checksum_print(const u_int8_t *); +char *sr_uuid_format(const struct sr_uuid *); +void sr_uuid_print(const struct sr_uuid *, int); +void sr_meta_print(const struct sr_metadata *); + +#endif + +/** @} + */ diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index c5d8bcc50a..454774c36a 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -58,11 +58,13 @@ extern hr_superblock_ops_t metadata_native_ops; extern hr_superblock_ops_t metadata_gmirror_ops; extern hr_superblock_ops_t metadata_gstripe_ops; +extern hr_superblock_ops_t metadata_softraid_ops; static hr_superblock_ops_t *hr_superblock_ops_all[] = { [HR_METADATA_NATIVE] = &metadata_native_ops, [HR_METADATA_GEOM_MIRROR] = &metadata_gmirror_ops, - [HR_METADATA_GEOM_STRIPE] = &metadata_gstripe_ops + [HR_METADATA_GEOM_STRIPE] = &metadata_gstripe_ops, + [HR_METADATA_SOFTRAID] = &metadata_softraid_ops }; hr_superblock_ops_t *get_type_ops(hr_metadata_type_t type) From c9ef86459e6e21c1d427921416b3165bc69454e8 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Wed, 23 Apr 2025 13:01:37 +0200 Subject: [PATCH 199/324] hr: util.c: hr_create_vol_struct: HR_LVL_4 fallthrough --- uspace/srv/bd/hr/util.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 285da53e78..fd97610aa0 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -105,12 +105,6 @@ errno_t hr_create_vol_struct(hr_volume_t **rvol, hr_level_t level, vol->hr_ops.add_hotspare = hr_raid1_add_hotspare; break; case HR_LVL_4: - vol->hr_ops.create = hr_raid5_create; - vol->hr_ops.init = hr_raid5_init; - vol->hr_ops.status_event = hr_raid5_status_event; - if (meta_flags & HR_METADATA_HOTSPARE_SUPPORT) - vol->hr_ops.add_hotspare = hr_raid5_add_hotspare; - break; case HR_LVL_5: vol->hr_ops.create = hr_raid5_create; vol->hr_ops.init = hr_raid5_init; From 59ec1c50b10309c43384a55b7097714bcf40519a Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Wed, 23 Apr 2025 13:04:03 +0200 Subject: [PATCH 200/324] hr: util.c: fix possible null deref --- uspace/srv/bd/hr/util.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index fd97610aa0..d49e3086df 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -78,6 +78,8 @@ extern fibril_rwlock_t hr_volumes_lock; errno_t hr_create_vol_struct(hr_volume_t **rvol, hr_level_t level, const char *devname, hr_metadata_type_t metadata_type) { + HR_DEBUG("%s()", __func__); + errno_t rc; hr_volume_t *vol = calloc(1, sizeof(hr_volume_t)); @@ -809,7 +811,7 @@ static errno_t hr_util_assemble_from_matching_list(list_t *list, hr_volume_t *vol; rc = hr_create_vol_struct(&vol, level, devname, type); if (rc != EOK) - goto error; + return rc; meta_ops->init_meta2vol(list, vol); From 9bf95d4aa063c974b7c2fca5a36ca8eb2169f389 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Thu, 24 Apr 2025 10:43:41 +0200 Subject: [PATCH 201/324] hr: hr_softraid.c: remove dead code --- uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c index 83312b4295..6452a8225a 100644 --- a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c +++ b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c @@ -169,8 +169,6 @@ static errno_t meta_softraid_init_meta2vol(const list_t *list, hr_volume_t *vol) vol->extents[index].status = HR_EXT_ONLINE; else vol->extents[index].status = HR_EXT_INVALID; - - index++; } for (size_t i = 0; i < vol->extent_no; i++) { From 2100a4ec2c18b4505ec181563599b6f94c1d6c07 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 25 Apr 2025 14:40:27 +0200 Subject: [PATCH 202/324] uspace/lib/devices/hr: add OpenBSD softraid md type --- uspace/lib/device/include/hr.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index 44db1658e8..b794bbeb20 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -113,8 +113,9 @@ typedef struct hr_vol_info { typedef enum { HR_METADATA_NATIVE = 0, - HR_METADATA_GEOM_MIRROR = 1, - HR_METADATA_GEOM_STRIPE = 2, + HR_METADATA_GEOM_MIRROR, + HR_METADATA_GEOM_STRIPE, + HR_METADATA_SOFTRAID, HR_METADATA_LAST_DUMMY } hr_metadata_type_t; From 40f56a486e4e6d080c9d27e70f0b2c088b246eb6 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 2 May 2025 17:02:22 +0200 Subject: [PATCH 203/324] hr: metadata/softraid: use inttypes.h specifiers --- .../hr/metadata/foreign/softraid/softraid.c | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/uspace/srv/bd/hr/metadata/foreign/softraid/softraid.c b/uspace/srv/bd/hr/metadata/foreign/softraid/softraid.c index d501dfbe87..06b1147fc0 100644 --- a/uspace/srv/bd/hr/metadata/foreign/softraid/softraid.c +++ b/uspace/srv/bd/hr/metadata/foreign/softraid/softraid.c @@ -76,47 +76,47 @@ sr_meta_print(const struct sr_metadata *m) struct sr_meta_opt_hdr *omh; /* TODO XXX: use PRI for portability */ - printf("\tssd_magic 0x%lx\n", m->ssdi.ssd_magic); - printf("\tssd_version %d\n", m->ssdi.ssd_version); - printf("\tssd_vol_flags 0x%x\n", m->ssdi.ssd_vol_flags); + printf("\tssd_magic 0x%" PRIx64 "\n", m->ssdi.ssd_magic); + printf("\tssd_version %" PRId32 "\n", m->ssdi.ssd_version); + printf("\tssd_vol_flags 0x%" PRIx32 "\n", m->ssdi.ssd_vol_flags); printf("\tssd_uuid "); sr_uuid_print(&m->ssdi.ssd_uuid, 1); - printf("\tssd_chunk_no %d\n", m->ssdi.ssd_chunk_no); - printf("\tssd_chunk_id %d\n", m->ssdi.ssd_chunk_id); - printf("\tssd_opt_no %d\n", m->ssdi.ssd_opt_no); - printf("\tssd_volid %d\n", m->ssdi.ssd_volid); - printf("\tssd_level %d\n", m->ssdi.ssd_level); - printf("\tssd_size %ld\n", m->ssdi.ssd_size); + printf("\tssd_chunk_no %" PRId32 "\n", m->ssdi.ssd_chunk_no); + printf("\tssd_chunk_id %" PRId32 "\n", m->ssdi.ssd_chunk_id); + printf("\tssd_opt_no %" PRId32 "\n", m->ssdi.ssd_opt_no); + printf("\tssd_volid %" PRId32 "\n", m->ssdi.ssd_volid); + printf("\tssd_level %" PRId32 "\n", m->ssdi.ssd_level); + printf("\tssd_size %" PRId64 "\n", m->ssdi.ssd_size); printf("\tssd_devname %s\n", m->ssd_devname); printf("\tssd_vendor %s\n", m->ssdi.ssd_vendor); printf("\tssd_product %s\n", m->ssdi.ssd_product); printf("\tssd_revision %s\n", m->ssdi.ssd_revision); - printf("\tssd_strip_size %d\n", m->ssdi.ssd_strip_size); + printf("\tssd_strip_size %" PRId32 "\n", m->ssdi.ssd_strip_size); printf("\tssd_checksum "); sr_checksum_print(m->ssd_checksum); printf("\n"); - printf("\tssd_meta_flags 0x%x\n", m->ssd_meta_flags); - printf("\tssd_ondisk %lu\n", m->ssd_ondisk); + printf("\tssd_meta_flags 0x%" PRIx32 "\n", m->ssd_meta_flags); + printf("\tssd_ondisk %" PRId64 "\n", m->ssd_ondisk); mc = (struct sr_meta_chunk *)(m + 1); for (i = 0; i < m->ssdi.ssd_chunk_no; i++, mc++) { - printf("\t\tscm_volid %d\n", mc->scmi.scm_volid); - printf("\t\tscm_chunk_id %d\n", mc->scmi.scm_chunk_id); + printf("\t\tscm_volid %" PRId32 "\n", mc->scmi.scm_volid); + printf("\t\tscm_chunk_id %" PRId32 "\n", mc->scmi.scm_chunk_id); printf("\t\tscm_devname %s\n", mc->scmi.scm_devname); - printf("\t\tscm_size %ld\n", mc->scmi.scm_size); - printf("\t\tscm_coerced_size %ld\n", mc->scmi.scm_coerced_size); + printf("\t\tscm_size %" PRId64 "\n", mc->scmi.scm_size); + printf("\t\tscm_coerced_size %" PRId64 "\n", mc->scmi.scm_coerced_size); printf("\t\tscm_uuid "); sr_uuid_print(&mc->scmi.scm_uuid, 1); printf("\t\tscm_checksum "); sr_checksum_print(mc->scm_checksum); printf("\n"); - printf("\t\tscm_status %d\n", mc->scm_status); + printf("\t\tscm_status %" PRId32 "\n", mc->scm_status); } omh = (struct sr_meta_opt_hdr *)((u_int8_t *)(m + 1) + sizeof(struct sr_meta_chunk) * m->ssdi.ssd_chunk_no); for (i = 0; i < m->ssdi.ssd_opt_no; i++) { - printf("\t\t\tsom_type %d\n", omh->som_type); + printf("\t\t\tsom_type %" PRId32 "\n", omh->som_type); printf("\t\t\tsom_checksum "); sr_checksum_print(omh->som_checksum); printf("\n"); From d1d355f9820c7738d073714c023e911fa335637a Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 6 May 2025 23:30:30 +0200 Subject: [PATCH 204/324] hr: refactor hrctl and some hr IPC methods --- uspace/app/hrctl/hrctl.c | 568 ++++++++++++++++------------- uspace/lib/device/include/hr.h | 6 +- uspace/lib/device/include/ipc/hr.h | 2 + uspace/lib/device/src/hr.c | 72 +++- uspace/srv/bd/hr/hr.c | 80 +++- uspace/srv/bd/hr/util.c | 71 ++-- uspace/srv/bd/hr/util.h | 2 +- 7 files changed, 490 insertions(+), 311 deletions(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index 8ccafbe42a..db795f0958 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -42,91 +42,90 @@ #include #include -#define HRCTL_SAMPLE_CONFIG_PATH "/cfg/sample_hr_config.sif" +/* #define HRCTL_SAMPLE_CONFIG_PATH "/cfg/sample_hr_config.sif" */ + +#define NAME "hrctl" static void usage(void); -static errno_t fill_config_devs(int, char **, int, hr_config_t *); +static errno_t fill_config_devs(int, char **, hr_config_t *); static errno_t load_config(const char *, hr_config_t *); static const char usage_str[] = - "Usage: hrctl [OPTION]... -n ...\n" + "Usage: hrctl [OPTION]...\n" "\n" "Options:\n" - " -h, --help display this message and exit\n" - " -C, --create-file=PATH create an array from file,\n" - " sample file at: " HRCTL_SAMPLE_CONFIG_PATH "\n" - " -A, --auto-assemble try to auto assemble all valid arrays\n" - " -s, --status display status of active arrays\n" - " -H, --hotspare=DEV add hotspare extent\n" - " -D, --destroy destroy/disassemble an active array\n" - " -F, --fail-extent fail an extent, use with -D and set it before\n" - " -c, --create=NAME create new array\n" - " -a, --assemble try to assemble from specified extents\n" - " -n non-zero number of devices\n" - " -l, --level=LEVEL set the RAID level,\n" - " valid values: 0, 1, 4, 5\n" - " -0 striping\n" - " -1 mirroring\n" - " -4 parity on one extent\n" - " -5 distributed parity\n" + " -h, --help Display this message and exit.\n" + "\n" + " -c, --create Create a volume, options:\n" + " name {-l , --level level} device... manual device specification, or\n" + " -f configuration.sif create from configuration file.\n" + "\n" + " -a, --assemble Assemble volume(s), options:\n" + " [device...] manual device specification, or\n" + " [-f configuration.sif] assemble from configuration file, or\n" + " no option is automatic assembly.\n" + "\n" + " -d, --disassemble Deactivate/disassemble, options:\n" + " [volume] specific volume, or\n" + " all volumes with no specified option.\n" + "\n" + " -m, --modify volume Modify a volume, options:\n" + " -f, --fail index fail an extent, or\n" + " -h, --hotspare device add hotspare.\n" "\n" - "When specifying name for creation or assembly, the device name\n" - "is automatically prepended with \"devices/\" prefix.\n" + " -s, --status Display status of active volumes.\n" "\n" "Example usage:\n" - " hrctl --create hr0 -0 -n 2 devices/\\hw\\0 devices/\\hw\\1\n" - " - creates new mirroring RAID device named /hr0 consisting\n" - " of 2 drives\n" - " hrctl --assemble -n 2 devices/\\hw\\0 devices/\\hw\\1\n" - " - assembles RAID devices from specified extents,\n" - " that were previously in an (active) array\n" - " hrctl devices/hr0 --hotspare=devices/disk10\n" - " - adds \"devices/disk10\" as hotspare extent\n" - " hrctl -F 0 -D devices/hr0\n" - " - marks first extent as FAILED\n" + "\t\thrctl --create hr0 --level 5 disk1 disk2 disk3\n" + "\t\thrctl -c hr0 -l 5 disk1 disk2 disk3\n" + "\t\thrctl -c -f cfg.sif\n" + "\t\thrctl --assemble disk1 disk2 disk3\n" + "\t\thrctl -a\n" + "\t\thrctl -d devices/hr0\n" + "\t\thrctl -d\n" + "\t\thrctl --modify devices/hr0 --fail 0\n" + "\t\thrctl --modify devices/hr0 --hotspare disk4\n" + "\t\thrctl -s\n" + "\n" + "Volume service names are automatically prepended with \"devices/\" prefix.\n" + "\n" "Limitations:\n" - " - device name must be less than 32 characters in size\n"; - -static struct option const long_options[] = { - { "help", no_argument, 0, 'h' }, - { "status", no_argument, 0, 's' }, - { "assemble", no_argument, 0, 'a' }, - { "create", required_argument, 0, 'c' }, - { "level", required_argument, 0, 'l' }, - { "create-file", required_argument, 0, 'C' }, - { "auto-assemble", no_argument, 0, 'A' }, - { "destroy", required_argument, 0, 'D' }, - { "fail-extent", required_argument, 0, 'F' }, - { "hotspare", required_argument, 0, 'H' }, - { 0, 0, 0, 0 } -}; + "\t- volume name must be shorter than 32 characters\n"; static void usage(void) { printf("%s", usage_str); } -static errno_t fill_config_devs(int argc, char **argv, int optind, - hr_config_t *cfg) +static errno_t fill_config_devs(int argc, char **argv, hr_config_t *cfg) { errno_t rc; size_t i; - for (i = 0; i < cfg->dev_no; i++) { + for (i = 0; i < HR_MAX_EXTENTS; i++) { rc = loc_service_get_id(argv[optind], &cfg->devs[i], 0); if (rc == ENOENT) { - printf("hrctl: no device \"%s\", marking as missing\n", + printf(NAME ": device \"%s\" not found, aborting\n", argv[optind]); - cfg->devs[i] = 0; + return ENOENT; } else if (rc != EOK) { - printf("hrctl: error resolving device \"%s\", aborting\n", + printf(NAME ": error resolving device \"%s\", aborting\n", argv[optind]); return EINVAL; } - optind++; + if (++optind >= argc) + break; + } + + if (optind < argc) { + printf(NAME ": too many devices specified, max = %u\n", + HR_MAX_EXTENTS); + return ELIMIT; } + cfg->dev_no = i; + return EOK; } @@ -225,225 +224,300 @@ static errno_t load_config(const char *path, hr_config_t *cfg) return rc; } -int main(int argc, char **argv) +static int handle_create(int argc, char **argv) { - errno_t rc; - int retval, c; - bool create, assemble; - long fail_extent = -1; - hr_t *hr = NULL; - hr_config_t *cfg; + if (optind >= argc) { + printf(NAME ": no arguments to --create\n"); + return EXIT_FAILURE; + } - cfg = calloc(1, sizeof(hr_config_t)); - if (cfg == NULL) - return 1; + hr_config_t *vol_config = calloc(1, sizeof(hr_config_t)); + if (vol_config == NULL) { + printf(NAME ": not enough memory"); + return ENOMEM; + } - retval = 0; - cfg->level = HR_LVL_UNKNOWN; - cfg->dev_no = 0; - create = assemble = false; + if (str_cmp(argv[optind], "-f") == 0) { + if (++optind >= argc) { + printf(NAME ": not enough arguments\n"); + goto error; + } + const char *config_path = argv[optind++]; + errno_t rc = load_config(config_path, vol_config); + if (rc != EOK) { + printf(NAME ": config parsing failed\n"); + goto error; + } + } else { + /* we need name + --level + arg + at least one extent */ + if (optind + 3 >= argc) { + printf(NAME ": not enough arguments\n"); + goto error; + } - if (argc < 2) { - goto bad; - } + const char *name = argv[optind++]; + if (str_size(name) >= HR_DEVNAME_LEN) { + printf(NAME ": devname must be less then 32 bytes.\n"); + goto error; + } - c = 0; - optreset = 1; - optind = 0; + str_cpy(vol_config->devname, HR_DEVNAME_LEN, name); - while (c != -1) { - c = getopt_long(argc, argv, "hsC:c:Aal:0145Ln:D:F:H:", - long_options, NULL); - switch (c) { - case 's': - free(cfg); - rc = hr_print_status(); - if (rc != EOK) - return 1; - return 0; - case 'C': - /* only support 1 array inside config for now XXX */ - rc = load_config(optarg, cfg); - if (rc != EOK) { - printf("hrctl: failed to load config\n"); - free(cfg); - return 1; - } - create = true; - goto skip; - case 'c': - if (str_size(optarg) > sizeof(cfg->devname) - 1) { - printf("hrctl: device name too long\n"); - free(cfg); - return 1; - } - str_cpy(cfg->devname, sizeof(cfg->devname), optarg); - create = true; - break; - case 'A': - size_t cnt; - rc = hr_auto_assemble(&cnt); - if (rc != EOK) { - /* XXX: here have own error codes */ - printf("hrctl: auto assemble rc: %s\n", - str_error(rc)); - } else { - printf("hrctl: auto assembled %zu volumes\n", - cnt); - } - return rc; - case 'a': - /* - * XXX: redo this, no devname, only svc ids... - * - * find some other way to rename the arrays..., - * - * some metadata editation tool... something like - * fdisk but can only change devnames on inactive - * extents... - */ - - /* - * XXX: remake whole parsing, don't allow -a - * to have any levels set or anything - */ - assemble = true; - break; - case 'D': - rc = hr_stop(optarg, fail_extent); - free(cfg); - if (rc != EOK) { - printf("hrctl: got %s\n", str_error(rc)); - return rc; - } - return 0; - case 'F': - fail_extent = strtol(optarg, NULL, 10); - break; - case 'l': - if (cfg->level != HR_LVL_UNKNOWN) - goto bad; - cfg->level = strtol(optarg, NULL, 10); - break; - case '0': - if (cfg->level != HR_LVL_UNKNOWN) - goto bad; - cfg->level = HR_LVL_0; - break; - case '1': - if (cfg->level != HR_LVL_UNKNOWN) - goto bad; - cfg->level = HR_LVL_1; - break; - case '4': - if (cfg->level != HR_LVL_UNKNOWN) - goto bad; - cfg->level = HR_LVL_4; - break; - case '5': - if (cfg->level != HR_LVL_UNKNOWN) - goto bad; - cfg->level = HR_LVL_5; - break; - case 'n': - cfg->dev_no = strtol(optarg, NULL, 10); - if ((int)cfg->dev_no + optind != argc) - goto bad; - rc = fill_config_devs(argc, argv, optind, cfg); - if (rc != EOK) { - free(cfg); - return 1; - } - goto skip; - case 'H': - if (optind != 3 && argc != 4) - goto bad; - - service_id_t hotspare; - service_id_t vol_svc_id; - - rc = loc_service_get_id(argv[1], &vol_svc_id, 0); - if (rc != EOK) { - printf("hrctl: error resolving volume \"%s\", " - "aborting extent addition\n", argv[1]); - goto bad; - } - - rc = loc_service_get_id(optarg, &hotspare, 0); - if (rc != EOK) { - printf("hrctl: error resolving device \"%s\", " - "aborting extent addition\n", optarg); - goto bad; - } - - rc = hr_add_hotspare(vol_svc_id, hotspare); - if (rc != EOK) - printf("hrctl: hr_add_hotspare() rc: %s\n", - str_error(rc)); - - free(cfg); - if (rc != EOK) - return 1; - else - return 0; - case 'h': - default: - usage(); - free(cfg); - return 0; + const char *level_opt = argv[optind++]; + if (str_cmp(level_opt, "--level") != 0 && + str_cmp(level_opt, "-l") != 0) { + printf(NAME ": unknown option \"%s\"\n", level_opt); + goto error; } - } -skip: - if ((create && assemble) || (!create && !assemble)) - goto bad; + vol_config->level = strtol(argv[optind++], NULL, 10); - if (create && cfg->level == HR_LVL_UNKNOWN) { - printf("hrctl: invalid level, exiting\n"); - goto bad; + errno_t rc = fill_config_devs(argc, argv, vol_config); + if (rc != EOK) + goto error; } - if (cfg->dev_no > HR_MAX_EXTENTS) { - printf("hrctl: too many devices, exiting\n"); - goto bad; + if (optind < argc) { + printf(NAME ": unexpected arguments\n"); + goto error; } - if (cfg->dev_no == 0) { - printf("hrctl: invalid number of devices, exiting\n"); - goto bad; + hr_t *hr; + errno_t rc = hr_sess_init(&hr); + if (rc != EOK) { + printf(NAME ": server session init failed: %s\n", + str_error(rc)); + goto error; } - rc = hr_sess_init(&hr); + rc = hr_create(hr, vol_config); if (rc != EOK) { - printf("hrctl: hr_sess_init() rc: %s\n", str_error(rc)); - retval = 1; - goto end; + printf(NAME ": creation failed: %s\n", + str_error(rc)); + goto error; } - if (create) { - rc = hr_create(hr, cfg); - printf("hrctl: hr_create() rc: %s\n", str_error(rc)); - } else if (assemble) { - size_t assembled_cnt = 0; - rc = hr_assemble(hr, cfg, &assembled_cnt); + hr_sess_destroy(hr); + + free(vol_config); + return EXIT_SUCCESS; +error: + free(vol_config); + return EXIT_FAILURE; +} + +static int handle_assemble(int argc, char **argv) +{ + if (optind >= argc) { + size_t cnt; + errno_t rc = hr_auto_assemble(&cnt); if (rc != EOK) { /* XXX: here have own error codes */ printf("hrctl: auto assemble rc: %s\n", str_error(rc)); - } else { - printf("hrctl: auto assembled %zu volumes\n", - assembled_cnt); + return EXIT_FAILURE; } + printf(NAME ": auto assembled %zu volumes\n", cnt); + return EXIT_SUCCESS; } -end: - free(cfg); + hr_config_t *vol_config = calloc(1, sizeof(hr_config_t)); + if (vol_config == NULL) { + printf(NAME ": not enough memory"); + return ENOMEM; + } + + if (str_cmp(argv[optind], "-f") == 0) { + if (++optind >= argc) { + printf(NAME ": not enough arguments\n"); + goto error; + } + const char *config_path = argv[optind++]; + errno_t rc = load_config(config_path, vol_config); + if (rc != EOK) { + printf(NAME ": config parsing failed\n"); + goto error; + } + if (optind < argc) { + printf(NAME ": unexpected arguments\n"); + goto error; + } + } else { + errno_t rc = fill_config_devs(argc, argv, vol_config); + if (rc != EOK) + goto error; + } + + hr_t *hr; + errno_t rc = hr_sess_init(&hr); + if (rc != EOK) { + printf(NAME ": server session init failed: %s\n", + str_error(rc)); + goto error; + } + + size_t cnt; + rc = hr_assemble(hr, vol_config, &cnt); + if (rc != EOK) { + printf(NAME ": assmeble failed: %s\n", str_error(rc)); + goto error; + } + + printf("hrctl: auto assembled %zu volumes\n", cnt); + hr_sess_destroy(hr); - return retval; -bad: - free(cfg); - printf("hrctl: bad usage, try hrctl --help\n"); - return 1; + + free(vol_config); + return EXIT_SUCCESS; +error: + free(vol_config); + return EXIT_FAILURE; +} + +static int handle_disassemble(int argc, char **argv) +{ + if (optind >= argc) { + errno_t rc = hr_stop_all(); + if (rc != EOK) { + printf(NAME ": stopping some volumes failed: %s\n", + str_error(rc)); + return EXIT_FAILURE; + } + return EXIT_SUCCESS; + } + + if (optind + 1 < argc) { + printf(NAME ": only 1 device can be manually specified\n"); + return EXIT_FAILURE; + } + + const char *devname = argv[optind++]; + + errno_t rc = hr_stop(devname); + if (rc != EOK) { + printf(NAME ": disassembly of device \"%s\" failed: %s\n", + devname, str_error(rc)); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +static int handle_modify(int argc, char **argv) +{ + if (optind >= argc) { + printf(NAME ": no arguments to --modify\n"); + return EXIT_FAILURE; + } + + const char *volname = argv[optind++]; + + /* at least 1 option and its agument */ + if (optind + 1 >= argc) { + printf(NAME ": not enough arguments\n"); + return EXIT_FAILURE; + } + + if (optind + 2 < argc) { + printf(NAME ": unexpected arguments\n"); + return EXIT_FAILURE; + } + + if (str_cmp(argv[optind], "--fail") == 0 || + str_cmp(argv[optind], "-f") == 0) { + optind++; + unsigned long extent = strtol(argv[optind++], NULL, 10); + errno_t rc = hr_fail_extent(volname, extent); + if (rc != EOK) { + printf(NAME ": failing extent failed: %s\n", + str_error(rc)); + return EXIT_FAILURE; + } + } else if (str_cmp(argv[optind], "--hotspare") == 0 || + str_cmp(argv[optind], "-h") == 0) { + optind++; + errno_t rc = hr_add_hotspare(volname, argv[optind++]); + if (rc != EOK) { + printf(NAME ": adding hotspare failed: %s\n", + str_error(rc)); + return EXIT_FAILURE; + } + } else { + printf(NAME ": unknown argument\n"); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +static int handle_status(int argc, char **argv) +{ + (void)argc; + (void)argv; + + errno_t rc = hr_print_status(); + if (rc != EOK) { + printf(NAME ": status printing failed: %s\n", str_error(rc)); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +int main(int argc, char **argv) +{ + int rc = EXIT_SUCCESS; + int c; + + if (argc < 2) { + rc = EXIT_FAILURE; + goto end; + } + + c = 0; + optreset = 1; + optind = 0; + + struct option const top_level_opts[] = { + { "help", no_argument, 0, 'h' }, + { "create", no_argument, 0, 'c' }, + { "assemble", no_argument, 0, 'a' }, + { "disassemble", no_argument, 0, 'd' }, + { "modify", no_argument, 0, 'm' }, + { "status", no_argument, 0, 's' }, + { 0, 0, 0, 0 } + }; + + while (c != -1) { + c = getopt_long(argc, argv, "hcadms", top_level_opts, NULL); + switch (c) { + case 'h': + usage(); + return EXIT_SUCCESS; + case 'c': + rc = handle_create(argc, argv); + goto end; + case 'a': + rc = handle_assemble(argc, argv); + goto end; + case 'd': + rc = handle_disassemble(argc, argv); + goto end; + case 'm': + rc = handle_modify(argc, argv); + goto end; + case 's': + rc = handle_status(argc, argv); + goto end; + default: + goto end; + } + } + +end: + if (rc != EXIT_SUCCESS) + printf(NAME ": use --help to see usage\n"); + return rc; } /** @} diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index b794bbeb20..b092c49830 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -124,8 +124,10 @@ extern void hr_sess_destroy(hr_t *); extern errno_t hr_create(hr_t *, hr_config_t *); extern errno_t hr_assemble(hr_t *, hr_config_t *, size_t *); extern errno_t hr_auto_assemble(size_t *); -extern errno_t hr_stop(const char *, long); -extern errno_t hr_add_hotspare(service_id_t, service_id_t); +extern errno_t hr_stop(const char *); +extern errno_t hr_stop_all(void); +extern errno_t hr_fail_extent(const char *, unsigned long); +extern errno_t hr_add_hotspare(const char *, const char *); extern errno_t hr_print_status(void); extern const char *hr_get_vol_status_msg(hr_vol_status_t); extern const char *hr_get_ext_status_msg(hr_ext_status_t); diff --git a/uspace/lib/device/include/ipc/hr.h b/uspace/lib/device/include/ipc/hr.h index de5d686c30..3872675062 100644 --- a/uspace/lib/device/include/ipc/hr.h +++ b/uspace/lib/device/include/ipc/hr.h @@ -42,6 +42,8 @@ typedef enum { HR_ASSEMBLE, HR_AUTO_ASSEMBLE, HR_STOP, + HR_STOP_ALL, + HR_FAIL_EXTENT, HR_ADD_HOTSPARE, HR_STATUS } hr_request_t; diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index 218d17188b..c5c4585627 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -108,10 +108,7 @@ errno_t hr_create(hr_t *hr, hr_config_t *hr_config) async_exchange_end(exch); async_wait_for(req, &retval); - if (retval != EOK) - return retval; - - return EOK; + return retval; } errno_t hr_assemble(hr_t *hr, hr_config_t *hr_config, size_t *rassembled_cnt) @@ -268,7 +265,7 @@ static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info) return EOK; } -errno_t hr_stop(const char *devname, long extent) +errno_t hr_stop(const char *devname) { hr_t *hr; errno_t rc; @@ -288,18 +285,79 @@ errno_t hr_stop(const char *devname, long extent) rc = EINVAL; goto error; } - rc = async_req_2_0(exch, HR_STOP, svc_id, extent); + + rc = async_req_1_0(exch, HR_STOP, svc_id); + async_exchange_end(exch); +error: + hr_sess_destroy(hr); + return rc; +} + +errno_t hr_stop_all(void) +{ + hr_t *hr; + async_exch_t *exch; + errno_t rc; + + rc = hr_sess_init(&hr); + if (rc != EOK) + return rc; + + exch = async_exchange_begin(hr->sess); + if (exch == NULL) { + rc = EINVAL; + goto error; + } + + rc = async_req_0_0(exch, HR_STOP_ALL); + async_exchange_end(exch); +error: + hr_sess_destroy(hr); + return rc; +} + +errno_t hr_fail_extent(const char *volume_name, unsigned long extent) +{ + hr_t *hr; + errno_t rc; + async_exch_t *exch; + service_id_t vol_svc_id; + + rc = loc_service_get_id(volume_name, &vol_svc_id, 0); + if (rc != EOK) + return rc; + + rc = hr_sess_init(&hr); + if (rc != EOK) + return rc; + + exch = async_exchange_begin(hr->sess); + if (exch == NULL) { + rc = EINVAL; + goto error; + } + + rc = async_req_2_0(exch, HR_FAIL_EXTENT, vol_svc_id, extent); async_exchange_end(exch); error: hr_sess_destroy(hr); return rc; } -errno_t hr_add_hotspare(service_id_t vol_svc_id, service_id_t hs_svc_id) +errno_t hr_add_hotspare(const char *volume_name, const char *hotspare) { hr_t *hr; errno_t rc; async_exch_t *exch; + service_id_t vol_svc_id, hs_svc_id; + + rc = loc_service_get_id(volume_name, &vol_svc_id, 0); + if (rc != EOK) + return rc; + + rc = loc_service_get_id(hotspare, &hs_svc_id, 0); + if (rc != EOK) + return rc; rc = hr_sess_init(&hr); if (rc != EOK) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 51684e171d..0578c1acfc 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -60,6 +60,7 @@ static void hr_assemble_srv(ipc_call_t *); static void hr_auto_assemble_srv(ipc_call_t *); static void hr_stop_srv(ipc_call_t *); +static void hr_stop_all_srv(ipc_call_t *); static void hr_add_hotspare_srv(ipc_call_t *); static void hr_print_status_srv(ipc_call_t *); static void hr_ctl_conn(ipc_call_t *, void *); @@ -162,8 +163,7 @@ static void hr_create_srv(ipc_call_t *icall) list_append(&vol->lvolumes, &hr_volumes); fibril_rwlock_write_unlock(&hr_volumes_lock); - HR_DEBUG("created volume \"%s\" (%" PRIun ")\n", vol->devname, - vol->svc_id); + HR_NOTE("created volume \"%s\"\n", vol->devname); free(cfg); async_answer_0(icall, rc); @@ -274,11 +274,9 @@ static void hr_stop_srv(ipc_call_t *icall) errno_t rc = EOK; service_id_t svc_id; - long fail_extent; hr_volume_t *vol; svc_id = ipc_get_arg1(icall); - fail_extent = (long)ipc_get_arg2(icall); vol = hr_get_volume(svc_id); if (vol == NULL) { @@ -286,28 +284,68 @@ static void hr_stop_srv(ipc_call_t *icall) return; } - if (fail_extent == -1) { - rc = hr_remove_volume(svc_id); - if (rc != EOK) { - async_answer_0(icall, rc); - return; + rc = hr_remove_volume(vol); + + async_answer_0(icall, rc); +} + +static void hr_stop_all_srv(ipc_call_t *icall) +{ + HR_DEBUG("%s()", __func__); + + hr_volume_t *vol; + errno_t rc = EOK; + + while (true) { + fibril_rwlock_write_lock(&hr_volumes_lock); + if (list_empty(&hr_volumes)) { + fibril_rwlock_write_unlock(&hr_volumes_lock); + break; } - } else { - fibril_rwlock_write_lock(&vol->states_lock); - fibril_rwlock_read_lock(&vol->extents_lock); - /* TODO: maybe expose extent state callbacks */ - hr_update_ext_status(vol, fail_extent, HR_EXT_FAILED); - hr_mark_vol_state_dirty(vol); + vol = list_pop(&hr_volumes, hr_volume_t, lvolumes); - fibril_rwlock_read_unlock(&vol->extents_lock); - fibril_rwlock_write_unlock(&vol->states_lock); + fibril_rwlock_write_unlock(&hr_volumes_lock); - vol->hr_ops.status_event(vol); + rc = hr_remove_volume(vol); + if (rc != EOK) + break; } + async_answer_0(icall, rc); } +static void hr_fail_extent_srv(ipc_call_t *icall) +{ + HR_DEBUG("%s()", __func__); + + service_id_t svc_id; + size_t fail_extent; + hr_volume_t *vol; + + svc_id = (service_id_t)ipc_get_arg1(icall); + fail_extent = (size_t)ipc_get_arg2(icall); + + vol = hr_get_volume(svc_id); + if (vol == NULL) { + async_answer_0(icall, ENOENT); + return; + } + + fibril_rwlock_write_lock(&vol->states_lock); + fibril_rwlock_read_lock(&vol->extents_lock); + + hr_update_ext_status(vol, fail_extent, HR_EXT_FAILED); + hr_mark_vol_state_dirty(vol); + + fibril_rwlock_read_unlock(&vol->extents_lock); + fibril_rwlock_write_unlock(&vol->states_lock); + + vol->hr_ops.status_event(vol); + + async_answer_0(icall, EOK); +} + static void hr_add_hotspare_srv(ipc_call_t *icall) { HR_DEBUG("%s()", __func__); @@ -437,6 +475,12 @@ static void hr_ctl_conn(ipc_call_t *icall, void *arg) case HR_STOP: hr_stop_srv(&call); break; + case HR_STOP_ALL: + hr_stop_all_srv(&call); + break; + case HR_FAIL_EXTENT: + hr_fail_extent_srv(&call); + break; case HR_ADD_HOTSPARE: hr_add_hotspare_srv(&call); break; diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index d49e3086df..215f0c3449 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -161,6 +161,8 @@ errno_t hr_create_vol_struct(hr_volume_t **rvol, hr_level_t level, void hr_destroy_vol_struct(hr_volume_t *vol) { + HR_DEBUG("%s()", __func__); + if (vol == NULL) return; @@ -172,7 +174,7 @@ void hr_destroy_vol_struct(hr_volume_t *vol) hr_volume_t *hr_get_volume(service_id_t svc_id) { - HR_DEBUG("hr_get_volume(): (%" PRIun ")\n", svc_id); + HR_DEBUG("%s()", __func__); hr_volume_t *rvol = NULL; @@ -188,42 +190,41 @@ hr_volume_t *hr_get_volume(service_id_t svc_id) return rvol; } -errno_t hr_remove_volume(service_id_t svc_id) +errno_t hr_remove_volume(hr_volume_t *vol) { - HR_DEBUG("hr_remove_volume(): (%" PRIun ")\n", svc_id); - - errno_t rc; + HR_DEBUG("%s()", __func__); fibril_rwlock_write_lock(&hr_volumes_lock); - list_foreach(hr_volumes, lvolumes, hr_volume_t, vol) { - if (vol->svc_id == svc_id) { - int open_cnt = atomic_load_explicit(&vol->open_cnt, - memory_order_relaxed); - /* - * The "atomicity" of this if condition is provided - * by the write lock - no new bd connection can - * come, because we need to get the bd_srvs_t from - * volume, which we get from the list. - * (see hr_client_conn() in hr.c) - */ - if (open_cnt > 0) { - fibril_rwlock_write_unlock(&hr_volumes_lock); - return EBUSY; - } - list_remove(&vol->lvolumes); - fibril_rwlock_write_unlock(&hr_volumes_lock); - vol->meta_ops->save(vol, NO_STATE_CALLBACK); - - hr_destroy_vol_struct(vol); - - rc = loc_service_unregister(hr_srv, svc_id); - return rc; - } + int open_cnt = atomic_load_explicit(&vol->open_cnt, + memory_order_relaxed); + /* + * The atomicity of this if condition (and this whole + * operation) is provided by the write lock - no new + * bd connection can come, because we need to get the + * bd_srvs_t from the volume, which we get from the list. + * (see hr_client_conn() in hr.c) + */ + if (open_cnt > 0) { + fibril_rwlock_write_unlock(&hr_volumes_lock); + return EBUSY; } + list_remove(&vol->lvolumes); + fibril_rwlock_write_unlock(&hr_volumes_lock); - return ENOENT; + + /* save metadata, but we don't care about states anymore */ + (void)vol->meta_ops->save(vol, NO_STATE_CALLBACK); + + service_id_t svc_id = vol->svc_id; + + HR_NOTE("deactivating volume \"%s\"\n", vol->devname); + + hr_destroy_vol_struct(vol); + + errno_t rc = loc_service_unregister(hr_srv, svc_id); + return rc; } errno_t hr_init_extents_from_cfg(hr_volume_t *vol, hr_config_t *cfg) @@ -835,8 +836,6 @@ static errno_t hr_util_assemble_from_matching_list(list_t *list, if (rc != EOK) goto error; - fibril_rwlock_write_lock(&hr_volumes_lock); - /* * XXX: register it here * ... if it fails on EEXIST try different name... like + 1 on the end @@ -851,17 +850,17 @@ static errno_t hr_util_assemble_from_matching_list(list_t *list, * TODO: discuss */ rc = hr_register_volume(vol); - if (rc != EOK) { - fibril_rwlock_write_unlock(&hr_volumes_lock); + if (rc != EOK) goto error; - } (void)vol->meta_ops->save(vol, WITH_STATE_CALLBACK); + fibril_rwlock_write_lock(&hr_volumes_lock); list_append(&vol->lvolumes, &hr_volumes); - fibril_rwlock_write_unlock(&hr_volumes_lock); + HR_NOTE("assembled volume \"%s\"\n", vol->devname); + return EOK; error: hr_destroy_vol_struct(vol); diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index 52e0273a57..87c00e3386 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -70,7 +70,7 @@ extern errno_t hr_create_vol_struct(hr_volume_t **, hr_level_t, const char *, hr_metadata_type_t); extern void hr_destroy_vol_struct(hr_volume_t *); extern hr_volume_t *hr_get_volume(service_id_t); -extern errno_t hr_remove_volume(service_id_t); +extern errno_t hr_remove_volume(hr_volume_t *); extern errno_t hr_init_extents_from_cfg(hr_volume_t *, hr_config_t *); extern void hr_fini_devs(hr_volume_t *); extern errno_t hr_register_volume(hr_volume_t *); From c2f016024f0758994190e57db1b2f69bb231a150 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 6 May 2025 23:31:40 +0200 Subject: [PATCH 205/324] hr: util: add more checks for hotspare addition --- uspace/srv/bd/hr/util.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 215f0c3449..d9c1141394 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -1017,6 +1017,15 @@ errno_t hr_util_add_hotspare(hr_volume_t *vol, service_id_t hotspare) goto error; } + for (size_t i = 0; i < vol->hotspare_no; i++) { + if (vol->hotspares[i].svc_id == hotspare) { + HR_ERROR("%s(): hotspare (%" PRIun ") already used in " + "%s\n", __func__, hotspare, vol->devname); + rc = EEXIST; + goto error; + } + } + rc = block_init(hotspare); if (rc != EOK) goto error; @@ -1028,7 +1037,10 @@ errno_t hr_util_add_hotspare(hr_volume_t *vol, service_id_t hotspare) goto error; } - if (hs_blkno < vol->truncated_blkno - vol->meta_ops->get_size()) { + if (hs_blkno - vol->meta_ops->get_size() < vol->truncated_blkno) { + HR_ERROR("%s(): hotspare (%" PRIun ") doesn't have enough " + "blocks\n", __func__, hotspare); + rc = EINVAL; block_fini(hotspare); goto error; From 217d0fb82558ed2d41fafb35fa77968453c367b2 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 6 May 2025 23:56:36 +0200 Subject: [PATCH 206/324] hrctl: add notes about failing an extent --- uspace/app/hrctl/hrctl.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index db795f0958..671d583b63 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -70,7 +70,7 @@ static const char usage_str[] = " all volumes with no specified option.\n" "\n" " -m, --modify volume Modify a volume, options:\n" - " -f, --fail index fail an extent, or\n" + " -f, --fail index fail an extent (DANGEROUS), or\n" " -h, --hotspare device add hotspare.\n" "\n" " -s, --status Display status of active volumes.\n" @@ -87,7 +87,11 @@ static const char usage_str[] = "\t\thrctl --modify devices/hr0 --hotspare disk4\n" "\t\thrctl -s\n" "\n" - "Volume service names are automatically prepended with \"devices/\" prefix.\n" + "Notes:\n" + " Volume service names are automatically prepended with \"devices/\" prefix.\n" + " Simulating an extent failure with -m volume -f index is dangerous. It marks\n" + " metadata as dirty in other healthy extents, and therefore invalidates\n" + " the specified extent.\n" "\n" "Limitations:\n" "\t- volume name must be shorter than 32 characters\n"; From 13c236532d3f40b5bf64cf0c4999624f51289005 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Wed, 7 May 2025 00:05:28 +0200 Subject: [PATCH 207/324] hr: metadata/softraid: checksum in original endianness --- uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c index 6452a8225a..5897018062 100644 --- a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c +++ b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c @@ -245,16 +245,17 @@ static errno_t meta_softraid_decode(const void *block, void *md_v) md->ssdi.ssd_strip_size = uint32_t_le2host(scratch_md->ssdi.ssd_strip_size); - memcpy(md->ssd_checksum, scratch_md->ssd_checksum, MD5_DIGEST_LENGTH); - rc = create_hash((const uint8_t *)&md->ssdi, + rc = create_hash((const uint8_t *)&scratch_md->ssdi, sizeof(struct sr_meta_invariant), md5_hash, HASH_MD5); assert(rc == EOK); - if (memcmp(md5_hash, md->ssd_checksum, 16) != 0) { + if (memcmp(md5_hash, scratch_md->ssd_checksum, 16) != 0) { HR_DEBUG("ssd_checksum invalid\n"); rc = EINVAL; goto error; } + memcpy(md->ssd_checksum, scratch_md->ssd_checksum, MD5_DIGEST_LENGTH); + memcpy(md->ssd_devname, scratch_md->ssd_devname, 32); md->ssd_meta_flags = uint32_t_le2host(scratch_md->ssd_meta_flags); md->ssd_data_blkno = uint32_t_le2host(scratch_md->ssd_data_blkno); @@ -290,7 +291,7 @@ static errno_t meta_softraid_decode(const void *block, void *md_v) * [1]: https://marc.info/?l=openbsd-tech&m=174535579711235&w=2 */ /* - * rc = create_hash((const uint8_t *)&mc->scmi, + * rc = create_hash((const uint8_t *)&scratch_mc->scmi, * sizeof(struct sr_meta_chunk_invariant), md5_hash, HASH_MD5); * assert(rc == EOK); * if (memcmp(md5_hash, mc->scm_checksum, 16) != 0) { From 31eb568c5927e8499242f32edc67d70cfaf48cc7 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Wed, 7 May 2025 00:27:00 +0200 Subject: [PATCH 208/324] hr: comment hr.c a bit --- uspace/srv/bd/hr/hr.c | 66 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 56 insertions(+), 10 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 0578c1acfc..489addd2d3 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -30,7 +30,8 @@ * @{ */ /** - * @file + * @file hr.c + * @brief HelenRAID server methods. */ #include @@ -39,21 +40,16 @@ #include #include #include -#include #include #include #include #include -#include #include #include #include #include #include -#include "fge.h" -#include "io.h" -#include "superblock.h" #include "util.h" #include "var.h" @@ -63,7 +59,7 @@ static void hr_stop_srv(ipc_call_t *); static void hr_stop_all_srv(ipc_call_t *); static void hr_add_hotspare_srv(ipc_call_t *); static void hr_print_status_srv(ipc_call_t *); -static void hr_ctl_conn(ipc_call_t *, void *); +static void hr_ctl_conn(ipc_call_t *); static void hr_client_conn(ipc_call_t *, void *); loc_srv_t *hr_srv; @@ -72,6 +68,13 @@ fibril_rwlock_t hr_volumes_lock; static service_id_t ctl_sid; +/** Volume creation (server). + * + * Creates HelenRAID volume from parameters and + * devices specified in hr_config_t. + * + * @param icall hr_config_t + */ static void hr_create_srv(ipc_call_t *icall) { HR_DEBUG("%s()", __func__); @@ -174,6 +177,14 @@ static void hr_create_srv(ipc_call_t *icall) async_answer_0(icall, rc); } +/** Manual volume assembly (server). + * + * Tries to assemble a volume from devices in hr_config_t and + * sends the number of successful volumes assembled back to the + * client. + * + * @param icall hr_config_t + */ static void hr_assemble_srv(ipc_call_t *icall) { HR_DEBUG("%s()", __func__); @@ -233,6 +244,12 @@ static void hr_assemble_srv(ipc_call_t *icall) async_answer_0(icall, rc); } +/** Automatic volume assembly (server). + * + * Tries to assemble a volume from devices in disk location + * category and sends the number of successful volumes assembled + * back to client. + */ static void hr_auto_assemble_srv(ipc_call_t *icall) { HR_DEBUG("%s()", __func__); @@ -268,6 +285,10 @@ static void hr_auto_assemble_srv(ipc_call_t *icall) async_answer_0(icall, rc); } +/** Volume deactivation (server). + * + * Deactivates/detaches specified volume. + */ static void hr_stop_srv(ipc_call_t *icall) { HR_DEBUG("%s()", __func__); @@ -289,6 +310,10 @@ static void hr_stop_srv(ipc_call_t *icall) async_answer_0(icall, rc); } +/** Automatic volume deactivation (server). + * + * Tries to deactivate/detach all volumes. + */ static void hr_stop_all_srv(ipc_call_t *icall) { HR_DEBUG("%s()", __func__); @@ -315,6 +340,13 @@ static void hr_stop_all_srv(ipc_call_t *icall) async_answer_0(icall, rc); } +/** Simulate volume extent failure (server). + * + * Changes the specified extent's state to FAULTY. + * Other extents' metadata are marked as dirty, therefore + * it effectively invalides the specified extent as well + * for further uses. + */ static void hr_fail_extent_srv(ipc_call_t *icall) { HR_DEBUG("%s()", __func__); @@ -346,6 +378,10 @@ static void hr_fail_extent_srv(ipc_call_t *icall) async_answer_0(icall, EOK); } +/** Add hotspare to volume (server). + * + * Adds hotspare to a volume. + */ static void hr_add_hotspare_srv(ipc_call_t *icall) { HR_DEBUG("%s()", __func__); @@ -377,6 +413,10 @@ static void hr_add_hotspare_srv(ipc_call_t *icall) async_answer_0(icall, rc); } +/** Volume state printing (server). + * + * Prints info about all active volumes. + */ static void hr_print_status_srv(ipc_call_t *icall) { HR_DEBUG("%s()", __func__); @@ -446,7 +486,9 @@ static void hr_print_status_srv(ipc_call_t *icall) async_answer_0(icall, rc); } -static void hr_ctl_conn(ipc_call_t *icall, void *arg) +/** HelenRAID server control IPC methods crossroad. + */ +static void hr_ctl_conn(ipc_call_t *icall) { HR_DEBUG("%s()", __func__); @@ -493,6 +535,11 @@ static void hr_ctl_conn(ipc_call_t *icall, void *arg) } } +/** HelenRAID server IPC method crossroad. + * + * Distinguishes between control IPC and block device + * IPC calls. + */ static void hr_client_conn(ipc_call_t *icall, void *arg) { HR_DEBUG("%s()", __func__); @@ -502,9 +549,8 @@ static void hr_client_conn(ipc_call_t *icall, void *arg) service_id_t svc_id = ipc_get_arg2(icall); if (svc_id == ctl_sid) { - hr_ctl_conn(icall, arg); + hr_ctl_conn(icall); } else { - HR_DEBUG("bd_conn()\n"); vol = hr_get_volume(svc_id); if (vol == NULL) async_answer_0(icall, ENOENT); From ac4b70bf8312f968d622e8ccc709c20de51f7dcc Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Wed, 7 May 2025 12:39:54 +0200 Subject: [PATCH 209/324] hr: fail only failable extents --- uspace/srv/bd/hr/hr.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 489addd2d3..0b81b95ef8 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -364,14 +364,24 @@ static void hr_fail_extent_srv(ipc_call_t *icall) return; } - fibril_rwlock_write_lock(&vol->states_lock); fibril_rwlock_read_lock(&vol->extents_lock); + fibril_rwlock_write_lock(&vol->states_lock); - hr_update_ext_status(vol, fail_extent, HR_EXT_FAILED); - hr_mark_vol_state_dirty(vol); + switch (vol->extents[fail_extent].status) { + case HR_EXT_NONE: + case HR_EXT_MISSING: + case HR_EXT_FAILED: + fibril_rwlock_write_unlock(&vol->states_lock); + fibril_rwlock_read_unlock(&vol->extents_lock); + async_answer_0(icall, EINVAL); + return; + default: + hr_update_ext_status(vol, fail_extent, HR_EXT_FAILED); + hr_mark_vol_state_dirty(vol); + } - fibril_rwlock_read_unlock(&vol->extents_lock); fibril_rwlock_write_unlock(&vol->states_lock); + fibril_rwlock_read_unlock(&vol->extents_lock); vol->hr_ops.status_event(vol); From fc265b4367687fc2dca4a6d18ca2b8a6c4885ddb Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Wed, 7 May 2025 12:41:29 +0200 Subject: [PATCH 210/324] hr: IPC methods: don't create own hr_t session --- uspace/app/hrctl/hrctl.c | 103 ++++++++++++++------------------- uspace/lib/device/include/hr.h | 12 ++-- uspace/lib/device/src/hr.c | 50 +++------------- 3 files changed, 57 insertions(+), 108 deletions(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index 671d583b63..07117fe99d 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -228,7 +228,7 @@ static errno_t load_config(const char *path, hr_config_t *cfg) return rc; } -static int handle_create(int argc, char **argv) +static int handle_create(hr_t *hr, int argc, char **argv) { if (optind >= argc) { printf(NAME ": no arguments to --create\n"); @@ -286,23 +286,13 @@ static int handle_create(int argc, char **argv) goto error; } - hr_t *hr; - errno_t rc = hr_sess_init(&hr); - if (rc != EOK) { - printf(NAME ": server session init failed: %s\n", - str_error(rc)); - goto error; - } - - rc = hr_create(hr, vol_config); + errno_t rc = hr_create(hr, vol_config); if (rc != EOK) { printf(NAME ": creation failed: %s\n", str_error(rc)); goto error; } - hr_sess_destroy(hr); - free(vol_config); return EXIT_SUCCESS; error: @@ -310,11 +300,11 @@ static int handle_create(int argc, char **argv) return EXIT_FAILURE; } -static int handle_assemble(int argc, char **argv) +static int handle_assemble(hr_t *hr, int argc, char **argv) { if (optind >= argc) { size_t cnt; - errno_t rc = hr_auto_assemble(&cnt); + errno_t rc = hr_auto_assemble(hr, &cnt); if (rc != EOK) { /* XXX: here have own error codes */ printf("hrctl: auto assemble rc: %s\n", str_error(rc)); @@ -352,16 +342,8 @@ static int handle_assemble(int argc, char **argv) goto error; } - hr_t *hr; - errno_t rc = hr_sess_init(&hr); - if (rc != EOK) { - printf(NAME ": server session init failed: %s\n", - str_error(rc)); - goto error; - } - size_t cnt; - rc = hr_assemble(hr, vol_config, &cnt); + errno_t rc = hr_assemble(hr, vol_config, &cnt); if (rc != EOK) { printf(NAME ": assmeble failed: %s\n", str_error(rc)); goto error; @@ -369,8 +351,6 @@ static int handle_assemble(int argc, char **argv) printf("hrctl: auto assembled %zu volumes\n", cnt); - hr_sess_destroy(hr); - free(vol_config); return EXIT_SUCCESS; error: @@ -378,10 +358,10 @@ static int handle_assemble(int argc, char **argv) return EXIT_FAILURE; } -static int handle_disassemble(int argc, char **argv) +static int handle_disassemble(hr_t *hr, int argc, char **argv) { if (optind >= argc) { - errno_t rc = hr_stop_all(); + errno_t rc = hr_stop_all(hr); if (rc != EOK) { printf(NAME ": stopping some volumes failed: %s\n", str_error(rc)); @@ -397,7 +377,7 @@ static int handle_disassemble(int argc, char **argv) const char *devname = argv[optind++]; - errno_t rc = hr_stop(devname); + errno_t rc = hr_stop(hr, devname); if (rc != EOK) { printf(NAME ": disassembly of device \"%s\" failed: %s\n", devname, str_error(rc)); @@ -407,7 +387,7 @@ static int handle_disassemble(int argc, char **argv) return EXIT_SUCCESS; } -static int handle_modify(int argc, char **argv) +static int handle_modify(hr_t *hr, int argc, char **argv) { if (optind >= argc) { printf(NAME ": no arguments to --modify\n"); @@ -431,7 +411,7 @@ static int handle_modify(int argc, char **argv) str_cmp(argv[optind], "-f") == 0) { optind++; unsigned long extent = strtol(argv[optind++], NULL, 10); - errno_t rc = hr_fail_extent(volname, extent); + errno_t rc = hr_fail_extent(hr, volname, extent); if (rc != EOK) { printf(NAME ": failing extent failed: %s\n", str_error(rc)); @@ -440,7 +420,7 @@ static int handle_modify(int argc, char **argv) } else if (str_cmp(argv[optind], "--hotspare") == 0 || str_cmp(argv[optind], "-h") == 0) { optind++; - errno_t rc = hr_add_hotspare(volname, argv[optind++]); + errno_t rc = hr_add_hotspare(hr, volname, argv[optind++]); if (rc != EOK) { printf(NAME ": adding hotspare failed: %s\n", str_error(rc)); @@ -454,12 +434,12 @@ static int handle_modify(int argc, char **argv) return EXIT_SUCCESS; } -static int handle_status(int argc, char **argv) +static int handle_status(hr_t *hr, int argc, char **argv) { (void)argc; (void)argv; - errno_t rc = hr_print_status(); + errno_t rc = hr_print_status(hr); if (rc != EOK) { printf(NAME ": status printing failed: %s\n", str_error(rc)); return EXIT_FAILURE; @@ -471,14 +451,19 @@ static int handle_status(int argc, char **argv) int main(int argc, char **argv) { int rc = EXIT_SUCCESS; - int c; + hr_t *hr = NULL; if (argc < 2) { rc = EXIT_FAILURE; goto end; } - c = 0; + if (hr_sess_init(&hr) != EOK) { + printf(NAME ": hr server session init failed: %s\n", + str_error(rc)); + return EXIT_FAILURE; + } + optreset = 1; optind = 0; @@ -492,33 +477,33 @@ int main(int argc, char **argv) { 0, 0, 0, 0 } }; - while (c != -1) { - c = getopt_long(argc, argv, "hcadms", top_level_opts, NULL); - switch (c) { - case 'h': - usage(); - return EXIT_SUCCESS; - case 'c': - rc = handle_create(argc, argv); - goto end; - case 'a': - rc = handle_assemble(argc, argv); - goto end; - case 'd': - rc = handle_disassemble(argc, argv); - goto end; - case 'm': - rc = handle_modify(argc, argv); - goto end; - case 's': - rc = handle_status(argc, argv); - goto end; - default: - goto end; - } + int c = getopt_long(argc, argv, "hcadms", top_level_opts, NULL); + switch (c) { + case 'h': + usage(); + goto end; + case 'c': + rc = handle_create(hr, argc, argv); + goto end; + case 'a': + rc = handle_assemble(hr, argc, argv); + goto end; + case 'd': + rc = handle_disassemble(hr, argc, argv); + goto end; + case 'm': + rc = handle_modify(hr, argc, argv); + goto end; + case 's': + rc = handle_status(hr, argc, argv); + goto end; + default: + goto end; } end: + hr_sess_destroy(hr); + if (rc != EXIT_SUCCESS) printf(NAME ": use --help to see usage\n"); return rc; diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index b092c49830..654482ddaa 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -123,12 +123,12 @@ extern errno_t hr_sess_init(hr_t **); extern void hr_sess_destroy(hr_t *); extern errno_t hr_create(hr_t *, hr_config_t *); extern errno_t hr_assemble(hr_t *, hr_config_t *, size_t *); -extern errno_t hr_auto_assemble(size_t *); -extern errno_t hr_stop(const char *); -extern errno_t hr_stop_all(void); -extern errno_t hr_fail_extent(const char *, unsigned long); -extern errno_t hr_add_hotspare(const char *, const char *); -extern errno_t hr_print_status(void); +extern errno_t hr_auto_assemble(hr_t *, size_t *); +extern errno_t hr_stop(hr_t *, const char *); +extern errno_t hr_stop_all(hr_t *); +extern errno_t hr_fail_extent(hr_t *, const char *, unsigned long); +extern errno_t hr_add_hotspare(hr_t *, const char *, const char *); +extern errno_t hr_print_status(hr_t *); extern const char *hr_get_vol_status_msg(hr_vol_status_t); extern const char *hr_get_ext_status_msg(hr_ext_status_t); extern const char *hr_get_layout_str(hr_layout_t); diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index c5c4585627..c044d467e4 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -147,16 +147,11 @@ errno_t hr_assemble(hr_t *hr, hr_config_t *hr_config, size_t *rassembled_cnt) return rc; } -errno_t hr_auto_assemble(size_t *rassembled_cnt) +errno_t hr_auto_assemble(hr_t *hr, size_t *rassembled_cnt) { - hr_t *hr; errno_t rc; size_t assembled_cnt; - rc = hr_sess_init(&hr); - if (rc != EOK) - return rc; - async_exch_t *exch = async_exchange_begin(hr->sess); if (exch == NULL) { rc = EINVAL; @@ -178,7 +173,6 @@ errno_t hr_auto_assemble(size_t *rassembled_cnt) if (rassembled_cnt != NULL) *rassembled_cnt = assembled_cnt; error: - hr_sess_destroy(hr); return rc; } @@ -265,9 +259,8 @@ static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info) return EOK; } -errno_t hr_stop(const char *devname) +errno_t hr_stop(hr_t *hr, const char *devname) { - hr_t *hr; errno_t rc; async_exch_t *exch; service_id_t svc_id; @@ -276,10 +269,6 @@ errno_t hr_stop(const char *devname) if (rc != EOK) return rc; - rc = hr_sess_init(&hr); - if (rc != EOK) - return rc; - exch = async_exchange_begin(hr->sess); if (exch == NULL) { rc = EINVAL; @@ -289,20 +278,14 @@ errno_t hr_stop(const char *devname) rc = async_req_1_0(exch, HR_STOP, svc_id); async_exchange_end(exch); error: - hr_sess_destroy(hr); return rc; } -errno_t hr_stop_all(void) +errno_t hr_stop_all(hr_t *hr) { - hr_t *hr; async_exch_t *exch; errno_t rc; - rc = hr_sess_init(&hr); - if (rc != EOK) - return rc; - exch = async_exchange_begin(hr->sess); if (exch == NULL) { rc = EINVAL; @@ -312,13 +295,11 @@ errno_t hr_stop_all(void) rc = async_req_0_0(exch, HR_STOP_ALL); async_exchange_end(exch); error: - hr_sess_destroy(hr); return rc; } -errno_t hr_fail_extent(const char *volume_name, unsigned long extent) +errno_t hr_fail_extent(hr_t *hr, const char *volume_name, unsigned long extent) { - hr_t *hr; errno_t rc; async_exch_t *exch; service_id_t vol_svc_id; @@ -327,10 +308,6 @@ errno_t hr_fail_extent(const char *volume_name, unsigned long extent) if (rc != EOK) return rc; - rc = hr_sess_init(&hr); - if (rc != EOK) - return rc; - exch = async_exchange_begin(hr->sess); if (exch == NULL) { rc = EINVAL; @@ -340,13 +317,11 @@ errno_t hr_fail_extent(const char *volume_name, unsigned long extent) rc = async_req_2_0(exch, HR_FAIL_EXTENT, vol_svc_id, extent); async_exchange_end(exch); error: - hr_sess_destroy(hr); return rc; } -errno_t hr_add_hotspare(const char *volume_name, const char *hotspare) +errno_t hr_add_hotspare(hr_t *hr, const char *volume_name, const char *hotspare) { - hr_t *hr; errno_t rc; async_exch_t *exch; service_id_t vol_svc_id, hs_svc_id; @@ -359,10 +334,6 @@ errno_t hr_add_hotspare(const char *volume_name, const char *hotspare) if (rc != EOK) return rc; - rc = hr_sess_init(&hr); - if (rc != EOK) - return rc; - exch = async_exchange_begin(hr->sess); if (exch == NULL) { rc = EINVAL; @@ -372,23 +343,17 @@ errno_t hr_add_hotspare(const char *volume_name, const char *hotspare) rc = async_req_2_0(exch, HR_ADD_HOTSPARE, vol_svc_id, hs_svc_id); async_exchange_end(exch); error: - hr_sess_destroy(hr); return rc; } -errno_t hr_print_status(void) +errno_t hr_print_status(hr_t *hr) { - hr_t *hr; errno_t rc, retval; async_exch_t *exch; aid_t req; size_t size, i; hr_vol_info_t *vols = NULL; - rc = hr_sess_init(&hr); - if (rc != EOK) - return rc; - exch = async_exchange_begin(hr->sess); if (exch == NULL) { rc = EINVAL; @@ -428,7 +393,7 @@ errno_t hr_print_status(void) } if (size == 0) { - printf("no active arrays\n"); + printf("no active volumes\n"); goto error; } @@ -439,7 +404,6 @@ errno_t hr_print_status(void) } error: - hr_sess_destroy(hr); if (vols != NULL) free(vols); return rc; From af4ecb76e05b5a44b9806df2c25c8bb7a5550326 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Wed, 7 May 2025 13:01:14 +0200 Subject: [PATCH 211/324] hr: document lib/device/src/hr.c --- uspace/lib/device/src/hr.c | 69 +++++++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index c044d467e4..9fcb768ac8 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -30,7 +30,7 @@ * @{ */ /** - * @file + * @file HelenRAID client API */ #include @@ -43,6 +43,12 @@ #include #include +/** Initialize server session. + * + * @param rhr Place to store inited session + * + * @return EOK on success or an error code + */ errno_t hr_sess_init(hr_t **rhr) { errno_t rc; @@ -78,6 +84,10 @@ errno_t hr_sess_init(hr_t **rhr) return rc; } +/** Destroy server session. + * + * @param hr Session to destroy + */ void hr_sess_destroy(hr_t *hr) { if (hr == NULL) @@ -87,6 +97,13 @@ void hr_sess_destroy(hr_t *hr) free(hr); } +/** Create volume. + * + * @param hr Server session + * @param hr_config Config to create from + * + * @return EOK on success or an error code + */ errno_t hr_create(hr_t *hr, hr_config_t *hr_config) { errno_t rc, retval; @@ -111,6 +128,14 @@ errno_t hr_create(hr_t *hr, hr_config_t *hr_config) return retval; } +/** Assemble volumes. + * + * @param hr Server session + * @param hr_config Config to assemble from + * @param rassembled_cnt Place to store assembled count + * + * @return EOK on success or an error code + */ errno_t hr_assemble(hr_t *hr, hr_config_t *hr_config, size_t *rassembled_cnt) { errno_t rc; @@ -147,6 +172,13 @@ errno_t hr_assemble(hr_t *hr, hr_config_t *hr_config, size_t *rassembled_cnt) return rc; } +/** Automatically assemble volumes. + * + * @param hr Server session + * @param rassembled_cnt Place to store assembled count + * + * @return EOK on success or an error code + */ errno_t hr_auto_assemble(hr_t *hr, size_t *rassembled_cnt) { errno_t rc; @@ -259,6 +291,13 @@ static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info) return EOK; } +/** Stop/deactivate volume. + * + * @param hr Server session + * @param devname Volume name + * + * @return EOK on success or an error code + */ errno_t hr_stop(hr_t *hr, const char *devname) { errno_t rc; @@ -281,6 +320,12 @@ errno_t hr_stop(hr_t *hr, const char *devname) return rc; } +/** Stop/deactivate all volumes. + * + * @param hr Server session + * + * @return EOK on success or an error code + */ errno_t hr_stop_all(hr_t *hr) { async_exch_t *exch; @@ -298,6 +343,14 @@ errno_t hr_stop_all(hr_t *hr) return rc; } +/** Fail an extent in volume. + * + * @param hr Server session + * @param volume_name Volume name + * @param extent Extent index to fail + * + * @return EOK on success or an error code + */ errno_t hr_fail_extent(hr_t *hr, const char *volume_name, unsigned long extent) { errno_t rc; @@ -320,6 +373,14 @@ errno_t hr_fail_extent(hr_t *hr, const char *volume_name, unsigned long extent) return rc; } +/** Add a hotspare to volume. + * + * @param hr Server session + * @param volume_name Volume name + * @param hotspare Hotspare service name + * + * @return EOK on success or an error code + */ errno_t hr_add_hotspare(hr_t *hr, const char *volume_name, const char *hotspare) { errno_t rc; @@ -346,6 +407,12 @@ errno_t hr_add_hotspare(hr_t *hr, const char *volume_name, const char *hotspare) return rc; } +/** Print state of volumes. + * + * @param hr Server session + * + * @return EOK on success or an error code + */ errno_t hr_print_status(hr_t *hr) { errno_t rc, retval; From 155d34fab0cbaad1a3fb64bb7f99b7e653b5d098 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Wed, 7 May 2025 13:08:31 +0200 Subject: [PATCH 212/324] hr: rename hr_get_*_status_msg -> hr_get_*_state_str --- uspace/lib/device/include/hr.h | 4 ++-- uspace/lib/device/src/hr.c | 38 +++++++++++++++++++++++++++------- uspace/srv/bd/hr/raid1.c | 2 +- uspace/srv/bd/hr/raid5.c | 2 +- uspace/srv/bd/hr/util.c | 10 ++++----- 5 files changed, 40 insertions(+), 16 deletions(-) diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index 654482ddaa..720fc5236f 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -129,8 +129,8 @@ extern errno_t hr_stop_all(hr_t *); extern errno_t hr_fail_extent(hr_t *, const char *, unsigned long); extern errno_t hr_add_hotspare(hr_t *, const char *, const char *); extern errno_t hr_print_status(hr_t *); -extern const char *hr_get_vol_status_msg(hr_vol_status_t); -extern const char *hr_get_ext_status_msg(hr_ext_status_t); +extern const char *hr_get_vol_state_str(hr_vol_status_t); +extern const char *hr_get_ext_state_str(hr_ext_status_t); extern const char *hr_get_layout_str(hr_layout_t); extern const char *hr_get_metadata_type_str(hr_metadata_type_t); diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index 9fcb768ac8..9245ebbe31 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -224,7 +224,7 @@ static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info) return rc; printf("devname: %s\n", devname); - printf("status: %s\n", hr_get_vol_status_msg(vol_info->status)); + printf("status: %s\n", hr_get_vol_state_str(vol_info->status)); printf("level: %d\n", vol_info->level); if (vol_info->level == HR_LVL_4 || vol_info->level == HR_LVL_5) { @@ -263,11 +263,11 @@ static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info) if ((i == 0 && vol_info->layout == HR_RLQ_RAID4_0) || (i == vol_info->extent_no - 1 && vol_info->layout == HR_RLQ_RAID4_N)) - printf(" P %s %zu %s\n", hr_get_ext_status_msg(ext->status), i, devname); + printf(" P %s %zu %s\n", hr_get_ext_state_str(ext->status), i, devname); else - printf(" %s %zu %s\n", hr_get_ext_status_msg(ext->status), i, devname); + printf(" %s %zu %s\n", hr_get_ext_state_str(ext->status), i, devname); } else { - printf(" %s %zu %s\n", hr_get_ext_status_msg(ext->status), i, devname); + printf(" %s %zu %s\n", hr_get_ext_state_str(ext->status), i, devname); } } @@ -285,7 +285,7 @@ static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info) return rc; } printf(" %s %zu %s\n", - hr_get_ext_status_msg(ext->status), i, devname); + hr_get_ext_state_str(ext->status), i, devname); } return EOK; @@ -476,7 +476,13 @@ errno_t hr_print_status(hr_t *hr) return rc; } -const char *hr_get_vol_status_msg(hr_vol_status_t status) +/** Get volume state string. + * + * @param state State value + * + * @return State string + */ +const char *hr_get_vol_state_str(hr_vol_status_t status) { switch (status) { case HR_VOL_NONE: @@ -494,7 +500,13 @@ const char *hr_get_vol_status_msg(hr_vol_status_t status) } } -const char *hr_get_ext_status_msg(hr_ext_status_t status) +/** Get extent state string. + * + * @param state State value + * + * @return State string + */ +const char *hr_get_ext_state_str(hr_ext_status_t status) { switch (status) { case HR_EXT_NONE: @@ -516,6 +528,12 @@ const char *hr_get_ext_status_msg(hr_ext_status_t status) } } +/** Get volume layout string. + * + * @param layout Layout value + * + * @return Layout string + */ const char *hr_get_layout_str(hr_layout_t layout) { switch (layout) { @@ -536,6 +554,12 @@ const char *hr_get_layout_str(hr_layout_t layout) } } +/** Get volume metadata type string. + * + * @param type Metadata type value + * + * @return Metadata type string + */ const char *hr_get_metadata_type_str(hr_metadata_type_t type) { switch (type) { diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index aedc42ca48..3f597b950a 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -608,7 +608,7 @@ static errno_t init_rebuild(hr_volume_t *vol, size_t *rebuild_idx) hr_ext_status_t hs_state = vol->hotspares[hotspare_idx].status; if (hs_state != HR_EXT_HOTSPARE) { HR_ERROR("hr_raid1_rebuild(): invalid hotspare state \"%s\", " - "aborting rebuild\n", hr_get_ext_status_msg(hs_state)); + "aborting rebuild\n", hr_get_ext_state_str(hs_state)); rc = EINVAL; goto error; } diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 445e1557e2..cc2507ed8d 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -744,7 +744,7 @@ static errno_t hr_raid5_rebuild(void *arg) hr_ext_status_t hs_state = vol->hotspares[hotspare_idx].status; if (hs_state != HR_EXT_HOTSPARE) { HR_ERROR("hr_raid5_rebuild(): invalid hotspare state \"%s\", " - "aborting rebuild\n", hr_get_ext_status_msg(hs_state)); + "aborting rebuild\n", hr_get_ext_state_str(hs_state)); rc = EINVAL; goto end; } diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index d9c1141394..b1164a11c6 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -384,8 +384,8 @@ void hr_update_ext_status(hr_volume_t *vol, size_t ext_idx, hr_ext_status_t s) hr_ext_status_t old = vol->extents[ext_idx].status; HR_NOTE("\"%s\": changing extent %zu state: %s -> %s\n", - vol->devname, ext_idx, hr_get_ext_status_msg(old), - hr_get_ext_status_msg(s)); + vol->devname, ext_idx, hr_get_ext_state_str(old), + hr_get_ext_state_str(s)); vol->extents[ext_idx].status = s; } @@ -398,8 +398,8 @@ void hr_update_hotspare_status(hr_volume_t *vol, size_t hs_idx, hr_ext_status_t old = vol->hotspares[hs_idx].status; HR_NOTE("\"%s\": changing hotspare %zu state: %s -> %s\n", - vol->devname, hs_idx, hr_get_ext_status_msg(old), - hr_get_ext_status_msg(s)); + vol->devname, hs_idx, hr_get_ext_state_str(old), + hr_get_ext_state_str(s)); vol->hotspares[hs_idx].status = s; } @@ -408,7 +408,7 @@ void hr_update_vol_status(hr_volume_t *vol, hr_vol_status_t new) assert(fibril_rwlock_is_write_locked(&vol->states_lock)); HR_NOTE("\"%s\": changing volume state: %s -> %s\n", vol->devname, - hr_get_vol_status_msg(vol->status), hr_get_vol_status_msg(new)); + hr_get_vol_state_str(vol->status), hr_get_vol_state_str(new)); vol->status = new; } From 56602e01dd921b17bea4aa87f346c2b2fea742a0 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Wed, 7 May 2025 13:26:23 +0200 Subject: [PATCH 213/324] hr: rename all strings `status' -> `state' --- uspace/app/hrctl/hrctl.c | 12 ++-- uspace/lib/device/include/hr.h | 20 +++--- uspace/lib/device/src/hr.c | 30 ++++---- uspace/srv/bd/hr/hr.c | 14 ++-- .../bd/hr/metadata/foreign/geom/hr_g_mirror.c | 10 +-- .../bd/hr/metadata/foreign/geom/hr_g_stripe.c | 8 +-- .../metadata/foreign/softraid/hr_softraid.c | 8 +-- uspace/srv/bd/hr/metadata/native.c | 14 ++-- uspace/srv/bd/hr/raid0.c | 28 ++++---- uspace/srv/bd/hr/raid1.c | 68 +++++++++---------- uspace/srv/bd/hr/raid5.c | 58 ++++++++-------- uspace/srv/bd/hr/util.c | 50 +++++++------- uspace/srv/bd/hr/util.h | 12 ++-- uspace/srv/bd/hr/var.h | 10 +-- 14 files changed, 171 insertions(+), 171 deletions(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index 07117fe99d..6bfcb2e1cb 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -73,7 +73,7 @@ static const char usage_str[] = " -f, --fail index fail an extent (DANGEROUS), or\n" " -h, --hotspare device add hotspare.\n" "\n" - " -s, --status Display status of active volumes.\n" + " -s, --state Display state of active volumes.\n" "\n" "Example usage:\n" "\t\thrctl --create hr0 --level 5 disk1 disk2 disk3\n" @@ -434,14 +434,14 @@ static int handle_modify(hr_t *hr, int argc, char **argv) return EXIT_SUCCESS; } -static int handle_status(hr_t *hr, int argc, char **argv) +static int handle_state(hr_t *hr, int argc, char **argv) { (void)argc; (void)argv; - errno_t rc = hr_print_status(hr); + errno_t rc = hr_print_state(hr); if (rc != EOK) { - printf(NAME ": status printing failed: %s\n", str_error(rc)); + printf(NAME ": state printing failed: %s\n", str_error(rc)); return EXIT_FAILURE; } @@ -473,7 +473,7 @@ int main(int argc, char **argv) { "assemble", no_argument, 0, 'a' }, { "disassemble", no_argument, 0, 'd' }, { "modify", no_argument, 0, 'm' }, - { "status", no_argument, 0, 's' }, + { "state", no_argument, 0, 's' }, { 0, 0, 0, 0 } }; @@ -495,7 +495,7 @@ int main(int argc, char **argv) rc = handle_modify(hr, argc, argv); goto end; case 's': - rc = handle_status(hr, argc, argv); + rc = handle_state(hr, argc, argv); goto end; default: goto end; diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index 720fc5236f..140501f048 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -63,23 +63,23 @@ typedef enum hr_layout { HR_RLQ_RAID5_NC /* RAID-5 Rotating Parity N with Data Continuation */ } hr_layout_t; -typedef enum hr_vol_status { +typedef enum hr_vol_state { HR_VOL_NONE = 0, /* Unknown/None */ HR_VOL_ONLINE, /* optimal */ HR_VOL_FAULTY, /* unusable */ HR_VOL_DEGRADED, /* not optimal */ HR_VOL_REBUILD /* rebuild in progress */ -} hr_vol_status_t; +} hr_vol_state_t; -typedef enum hr_ext_status { - HR_EXT_NONE = 0, /* unknown/none status */ +typedef enum hr_ext_state { + HR_EXT_NONE = 0, /* unknown/none state */ HR_EXT_INVALID, /* working but not consistent */ HR_EXT_ONLINE, /* ok */ HR_EXT_MISSING, /* offline */ HR_EXT_FAILED, HR_EXT_REBUILD, HR_EXT_HOTSPARE -} hr_ext_status_t; +} hr_ext_state_t; typedef struct hr { async_sess_t *sess; @@ -94,7 +94,7 @@ typedef struct hr_config { typedef struct hr_extent { service_id_t svc_id; - hr_ext_status_t status; + hr_ext_state_t state; } hr_extent_t; typedef struct hr_vol_info { @@ -107,7 +107,7 @@ typedef struct hr_vol_info { uint64_t nblocks; uint32_t strip_size; size_t bsize; - hr_vol_status_t status; + hr_vol_state_t state; uint8_t layout; } hr_vol_info_t; @@ -128,9 +128,9 @@ extern errno_t hr_stop(hr_t *, const char *); extern errno_t hr_stop_all(hr_t *); extern errno_t hr_fail_extent(hr_t *, const char *, unsigned long); extern errno_t hr_add_hotspare(hr_t *, const char *, const char *); -extern errno_t hr_print_status(hr_t *); -extern const char *hr_get_vol_state_str(hr_vol_status_t); -extern const char *hr_get_ext_state_str(hr_ext_status_t); +extern errno_t hr_print_state(hr_t *); +extern const char *hr_get_vol_state_str(hr_vol_state_t); +extern const char *hr_get_ext_state_str(hr_ext_state_t); extern const char *hr_get_layout_str(hr_layout_t); extern const char *hr_get_metadata_type_str(hr_metadata_type_t); diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index 9245ebbe31..fb2f0e6f87 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -224,7 +224,7 @@ static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info) return rc; printf("devname: %s\n", devname); - printf("status: %s\n", hr_get_vol_state_str(vol_info->status)); + printf("state: %s\n", hr_get_vol_state_str(vol_info->state)); printf("level: %d\n", vol_info->level); if (vol_info->level == HR_LVL_4 || vol_info->level == HR_LVL_5) { @@ -245,12 +245,12 @@ static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info) printf("block size: %zu\n", vol_info->bsize); if (vol_info->level == HR_LVL_4) - printf("extents: [P] [status] [index] [devname]\n"); + printf("extents: [P] [state] [index] [devname]\n"); else - printf("extents: [status] [index] [devname]\n"); + printf("extents: [state] [index] [devname]\n"); for (i = 0; i < vol_info->extent_no; i++) { ext = &vol_info->extents[i]; - if (ext->status == HR_EXT_MISSING || ext->status == HR_EXT_NONE) { + if (ext->state == HR_EXT_MISSING || ext->state == HR_EXT_NONE) { devname = (char *) "MISSING-devname"; } else { rc = loc_service_get_name(ext->svc_id, &devname); @@ -263,21 +263,21 @@ static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info) if ((i == 0 && vol_info->layout == HR_RLQ_RAID4_0) || (i == vol_info->extent_no - 1 && vol_info->layout == HR_RLQ_RAID4_N)) - printf(" P %s %zu %s\n", hr_get_ext_state_str(ext->status), i, devname); + printf(" P %s %zu %s\n", hr_get_ext_state_str(ext->state), i, devname); else - printf(" %s %zu %s\n", hr_get_ext_state_str(ext->status), i, devname); + printf(" %s %zu %s\n", hr_get_ext_state_str(ext->state), i, devname); } else { - printf(" %s %zu %s\n", hr_get_ext_state_str(ext->status), i, devname); + printf(" %s %zu %s\n", hr_get_ext_state_str(ext->state), i, devname); } } if (vol_info->hotspare_no == 0) return EOK; - printf("hotspares: [status] [index] [devname]\n"); + printf("hotspares: [state] [index] [devname]\n"); for (i = 0; i < vol_info->hotspare_no; i++) { ext = &vol_info->hotspares[i]; - if (ext->status == HR_EXT_MISSING) { + if (ext->state == HR_EXT_MISSING) { devname = (char *) "MISSING-devname"; } else { rc = loc_service_get_name(ext->svc_id, &devname); @@ -285,7 +285,7 @@ static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info) return rc; } printf(" %s %zu %s\n", - hr_get_ext_state_str(ext->status), i, devname); + hr_get_ext_state_str(ext->state), i, devname); } return EOK; @@ -413,7 +413,7 @@ errno_t hr_add_hotspare(hr_t *hr, const char *volume_name, const char *hotspare) * * @return EOK on success or an error code */ -errno_t hr_print_status(hr_t *hr) +errno_t hr_print_state(hr_t *hr) { errno_t rc, retval; async_exch_t *exch; @@ -482,9 +482,9 @@ errno_t hr_print_status(hr_t *hr) * * @return State string */ -const char *hr_get_vol_state_str(hr_vol_status_t status) +const char *hr_get_vol_state_str(hr_vol_state_t state) { - switch (status) { + switch (state) { case HR_VOL_NONE: return "NONE/UNKNOWN"; case HR_VOL_ONLINE: @@ -506,9 +506,9 @@ const char *hr_get_vol_state_str(hr_vol_status_t status) * * @return State string */ -const char *hr_get_ext_state_str(hr_ext_status_t status) +const char *hr_get_ext_state_str(hr_ext_state_t state) { - switch (status) { + switch (state) { case HR_EXT_NONE: return "NONE/UNKNOWN"; case HR_EXT_INVALID: diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 0b81b95ef8..ea922d0790 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -58,7 +58,7 @@ static void hr_auto_assemble_srv(ipc_call_t *); static void hr_stop_srv(ipc_call_t *); static void hr_stop_all_srv(ipc_call_t *); static void hr_add_hotspare_srv(ipc_call_t *); -static void hr_print_status_srv(ipc_call_t *); +static void hr_print_state_srv(ipc_call_t *); static void hr_ctl_conn(ipc_call_t *); static void hr_client_conn(ipc_call_t *, void *); @@ -367,7 +367,7 @@ static void hr_fail_extent_srv(ipc_call_t *icall) fibril_rwlock_read_lock(&vol->extents_lock); fibril_rwlock_write_lock(&vol->states_lock); - switch (vol->extents[fail_extent].status) { + switch (vol->extents[fail_extent].state) { case HR_EXT_NONE: case HR_EXT_MISSING: case HR_EXT_FAILED: @@ -376,14 +376,14 @@ static void hr_fail_extent_srv(ipc_call_t *icall) async_answer_0(icall, EINVAL); return; default: - hr_update_ext_status(vol, fail_extent, HR_EXT_FAILED); + hr_update_ext_state(vol, fail_extent, HR_EXT_FAILED); hr_mark_vol_state_dirty(vol); } fibril_rwlock_write_unlock(&vol->states_lock); fibril_rwlock_read_unlock(&vol->extents_lock); - vol->hr_ops.status_event(vol); + vol->hr_ops.state_event(vol); async_answer_0(icall, EOK); } @@ -427,7 +427,7 @@ static void hr_add_hotspare_srv(ipc_call_t *icall) * * Prints info about all active volumes. */ -static void hr_print_status_srv(ipc_call_t *icall) +static void hr_print_state_srv(ipc_call_t *icall) { HR_DEBUG("%s()", __func__); @@ -469,7 +469,7 @@ static void hr_print_status_srv(ipc_call_t *icall) info.nblocks = vol->data_blkno; info.strip_size = vol->strip_size; info.bsize = vol->bsize; - info.status = vol->status; + info.state = vol->state; info.layout = vol->layout; if (!async_data_read_receive(&call, &size)) { @@ -537,7 +537,7 @@ static void hr_ctl_conn(ipc_call_t *icall) hr_add_hotspare_srv(&call); break; case HR_STATUS: - hr_print_status_srv(&call); + hr_print_state_srv(&call); break; default: async_answer_0(&call, EINVAL); diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c index ff8c5de88f..e186395c1d 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c @@ -159,16 +159,16 @@ static errno_t meta_gmirror_init_meta2vol(const list_t *list, hr_volume_t *vol) /* for now no md_sync_offset handling for saved REBUILD */ if (iter_meta->md_genid == max_counter_val) - vol->extents[index].status = HR_EXT_ONLINE; + vol->extents[index].state = HR_EXT_ONLINE; else - vol->extents[index].status = HR_EXT_INVALID; + vol->extents[index].state = HR_EXT_INVALID; index++; } for (size_t i = 0; i < vol->extent_no; i++) { - if (vol->extents[i].status == HR_EXT_NONE) - vol->extents[i].status = HR_EXT_MISSING; + if (vol->extents[i].state == HR_EXT_NONE) + vol->extents[i].state = HR_EXT_MISSING; } error: @@ -222,7 +222,7 @@ static errno_t meta_gmirror_get_block(service_id_t dev, void **rblock) rc = block_read_direct(dev, blkno - 1, 1, block); /* - * XXX: here maybe call vol status event or the state callback... + * XXX: here maybe call vol state event or the state callback... * * but need to pass vol pointer */ diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c index 588073fc36..c3e0088ee0 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c @@ -166,12 +166,12 @@ static errno_t meta_gstripe_init_meta2vol(const list_t *list, hr_volume_t *vol) vol->extents[index].svc_id = iter->svc_id; iter->fini = false; - vol->extents[index].status = HR_EXT_ONLINE; + vol->extents[index].state = HR_EXT_ONLINE; } for (size_t i = 0; i < vol->extent_no; i++) { - if (vol->extents[i].status == HR_EXT_NONE) - vol->extents[i].status = HR_EXT_MISSING; + if (vol->extents[i].state == HR_EXT_NONE) + vol->extents[i].state = HR_EXT_MISSING; } error: @@ -226,7 +226,7 @@ static errno_t meta_gstripe_get_block(service_id_t dev, void **rblock) rc = block_read_direct(dev, blkno - 1, 1, block); /* - * XXX: here maybe call vol status event or the state callback... + * XXX: here maybe call vol state event or the state callback... * * but need to pass vol pointer */ diff --git a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c index 5897018062..4fbb0ac9d7 100644 --- a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c +++ b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c @@ -166,14 +166,14 @@ static errno_t meta_softraid_init_meta2vol(const list_t *list, hr_volume_t *vol) /* for now no ssd_rebuild handling for saved REBUILD */ if (iter_meta->ssd_ondisk == max_counter_val) - vol->extents[index].status = HR_EXT_ONLINE; + vol->extents[index].state = HR_EXT_ONLINE; else - vol->extents[index].status = HR_EXT_INVALID; + vol->extents[index].state = HR_EXT_INVALID; } for (size_t i = 0; i < vol->extent_no; i++) { - if (vol->extents[i].status == HR_EXT_NONE) - vol->extents[i].status = HR_EXT_MISSING; + if (vol->extents[i].state == HR_EXT_NONE) + vol->extents[i].state = HR_EXT_MISSING; } error: diff --git a/uspace/srv/bd/hr/metadata/native.c b/uspace/srv/bd/hr/metadata/native.c index 810bcd95c8..c90e1b0232 100644 --- a/uspace/srv/bd/hr/metadata/native.c +++ b/uspace/srv/bd/hr/metadata/native.c @@ -170,14 +170,14 @@ static errno_t meta_native_init_meta2vol(const list_t *list, hr_volume_t *vol) iter->fini = false; if (iter_meta->counter == max_counter_val) - vol->extents[iter_meta->index].status = HR_EXT_ONLINE; + vol->extents[iter_meta->index].state = HR_EXT_ONLINE; else - vol->extents[iter_meta->index].status = HR_EXT_INVALID; + vol->extents[iter_meta->index].state = HR_EXT_INVALID; } for (size_t i = 0; i < vol->extent_no; i++) { - if (vol->extents[i].status == HR_EXT_NONE) - vol->extents[i].status = HR_EXT_MISSING; + if (vol->extents[i].state == HR_EXT_NONE) + vol->extents[i].state = HR_EXT_MISSING; } return EOK; @@ -282,7 +282,7 @@ static errno_t meta_native_get_block(service_id_t dev, void **rblock) rc = block_read_direct(dev, blkno - 1, HR_NATIVE_META_SIZE, block); /* - * XXX: here maybe call vol status event or the state callback... + * XXX: here maybe call vol state event or the state callback... * * but need to pass vol pointer */ @@ -378,7 +378,7 @@ static errno_t meta_native_save(hr_volume_t *vol, bool with_state_callback) fibril_rwlock_read_lock(&vol->states_lock); /* TODO: special case for REBUILD */ - if (ext->status != HR_EXT_ONLINE) + if (ext->state != HR_EXT_ONLINE) continue; fibril_rwlock_read_unlock(&vol->states_lock); @@ -395,7 +395,7 @@ static errno_t meta_native_save(hr_volume_t *vol, bool with_state_callback) fibril_rwlock_read_unlock(&vol->extents_lock); if (with_state_callback) - vol->hr_ops.status_event(vol); + vol->hr_ops.state_event(vol); free(md_block); return EOK; diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index 9b5146c0b0..fd1478247d 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -52,7 +52,7 @@ #include "util.h" #include "var.h" -static void hr_raid0_update_vol_status(hr_volume_t *); +static void hr_raid0_update_vol_state(hr_volume_t *); static void hr_raid0_state_callback(hr_volume_t *, size_t, errno_t); static errno_t hr_raid0_bd_op(hr_bd_op_type_t, bd_srv_t *, aoff64_t, size_t, void *, const void *, size_t); @@ -91,8 +91,8 @@ errno_t hr_raid0_create(hr_volume_t *new_volume) return EINVAL; } - hr_raid0_update_vol_status(new_volume); - if (new_volume->status != HR_VOL_ONLINE) { + hr_raid0_update_vol_state(new_volume); + if (new_volume->state != HR_VOL_ONLINE) { HR_NOTE("\"%s\": unusable state, not creating\n", new_volume->devname); return EINVAL; @@ -129,11 +129,11 @@ errno_t hr_raid0_init(hr_volume_t *vol) return EOK; } -void hr_raid0_status_event(hr_volume_t *vol) +void hr_raid0_state_event(hr_volume_t *vol) { HR_DEBUG("%s()", __func__); - hr_raid0_update_vol_status(vol); + hr_raid0_update_vol_state(vol); } static errno_t hr_raid0_bd_open(bd_srvs_t *bds, bd_srv_t *bd) @@ -191,7 +191,7 @@ static errno_t hr_raid0_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb) return EOK; } -static void hr_raid0_update_vol_status(hr_volume_t *vol) +static void hr_raid0_update_vol_state(hr_volume_t *vol) { fibril_mutex_lock(&vol->md_lock); @@ -202,15 +202,15 @@ static void hr_raid0_update_vol_status(hr_volume_t *vol) fibril_rwlock_read_lock(&vol->states_lock); - hr_vol_status_t old_state = vol->status; + hr_vol_state_t old_state = vol->state; for (size_t i = 0; i < vol->extent_no; i++) { - if (vol->extents[i].status != HR_EXT_ONLINE) { + if (vol->extents[i].state != HR_EXT_ONLINE) { fibril_rwlock_read_unlock(&vol->states_lock); if (old_state != HR_VOL_FAULTY) { fibril_rwlock_write_lock(&vol->states_lock); - hr_update_vol_status(vol, HR_VOL_FAULTY); + hr_update_vol_state(vol, HR_VOL_FAULTY); fibril_rwlock_write_unlock(&vol->states_lock); } return; @@ -220,7 +220,7 @@ static void hr_raid0_update_vol_status(hr_volume_t *vol) if (old_state != HR_VOL_ONLINE) { fibril_rwlock_write_lock(&vol->states_lock); - hr_update_vol_status(vol, HR_VOL_ONLINE); + hr_update_vol_state(vol, HR_VOL_ONLINE); fibril_rwlock_write_unlock(&vol->states_lock); } } @@ -234,13 +234,13 @@ static void hr_raid0_state_callback(hr_volume_t *vol, size_t extent, errno_t rc) switch (rc) { case ENOENT: - hr_update_ext_status(vol, extent, HR_EXT_MISSING); + hr_update_ext_state(vol, extent, HR_EXT_MISSING); break; default: - hr_update_ext_status(vol, extent, HR_EXT_FAILED); + hr_update_ext_state(vol, extent, HR_EXT_FAILED); } - hr_update_vol_status(vol, HR_VOL_FAULTY); + hr_update_vol_state(vol, HR_VOL_FAULTY); fibril_rwlock_write_unlock(&vol->states_lock); } @@ -256,7 +256,7 @@ static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, uint8_t *data_read = dst; fibril_rwlock_read_lock(&vol->states_lock); - if (vol->status != HR_VOL_ONLINE) { + if (vol->state != HR_VOL_ONLINE) { fibril_rwlock_read_unlock(&vol->states_lock); return EIO; } diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 3f597b950a..ce48ee8299 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -55,7 +55,7 @@ #include "util.h" #include "var.h" -static void hr_raid1_update_vol_status(hr_volume_t *); +static void hr_raid1_update_vol_state(hr_volume_t *); static void hr_raid1_ext_state_callback(hr_volume_t *, size_t, errno_t); static size_t hr_raid1_count_good_extents(hr_volume_t *, uint64_t, size_t, uint64_t); @@ -109,10 +109,10 @@ errno_t hr_raid1_create(hr_volume_t *new_volume) /* force volume state update */ hr_mark_vol_state_dirty(new_volume); - hr_raid1_update_vol_status(new_volume); + hr_raid1_update_vol_state(new_volume); fibril_rwlock_read_lock(&new_volume->states_lock); - hr_vol_status_t state = new_volume->status; + hr_vol_state_t state = new_volume->state; fibril_rwlock_read_unlock(&new_volume->states_lock); if (state == HR_VOL_FAULTY || state == HR_VOL_NONE) { HR_NOTE("\"%s\": unusable state, not creating\n", @@ -139,11 +139,11 @@ errno_t hr_raid1_init(hr_volume_t *vol) return EOK; } -void hr_raid1_status_event(hr_volume_t *vol) +void hr_raid1_state_event(hr_volume_t *vol) { HR_DEBUG("%s()", __func__); - hr_raid1_update_vol_status(vol); + hr_raid1_update_vol_state(vol); } errno_t hr_raid1_add_hotspare(hr_volume_t *vol, service_id_t hotspare) @@ -152,7 +152,7 @@ errno_t hr_raid1_add_hotspare(hr_volume_t *vol, service_id_t hotspare) errno_t rc = hr_util_add_hotspare(vol, hotspare); - hr_raid1_update_vol_status(vol); + hr_raid1_update_vol_state(vol); return rc; } @@ -212,7 +212,7 @@ static errno_t hr_raid1_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb) return EOK; } -static void hr_raid1_update_vol_status(hr_volume_t *vol) +static void hr_raid1_update_vol_state(hr_volume_t *vol) { bool exp = true; @@ -230,7 +230,7 @@ static void hr_raid1_update_vol_status(hr_volume_t *vol) fibril_rwlock_read_lock(&vol->extents_lock); fibril_rwlock_read_lock(&vol->states_lock); - hr_vol_status_t old_state = vol->status; + hr_vol_state_t old_state = vol->state; size_t healthy = hr_count_extents(vol, HR_EXT_ONLINE); fibril_rwlock_read_unlock(&vol->states_lock); @@ -239,14 +239,14 @@ static void hr_raid1_update_vol_status(hr_volume_t *vol) if (healthy == 0) { if (old_state != HR_VOL_FAULTY) { fibril_rwlock_write_lock(&vol->states_lock); - hr_update_vol_status(vol, HR_VOL_FAULTY); + hr_update_vol_state(vol, HR_VOL_FAULTY); fibril_rwlock_write_unlock(&vol->states_lock); } } else if (healthy < vol->extent_no) { if (old_state != HR_VOL_REBUILD && old_state != HR_VOL_DEGRADED) { fibril_rwlock_write_lock(&vol->states_lock); - hr_update_vol_status(vol, HR_VOL_DEGRADED); + hr_update_vol_state(vol, HR_VOL_DEGRADED); fibril_rwlock_write_unlock(&vol->states_lock); } @@ -264,7 +264,7 @@ static void hr_raid1_update_vol_status(hr_volume_t *vol) } else { if (old_state != HR_VOL_ONLINE) { fibril_rwlock_write_lock(&vol->states_lock); - hr_update_vol_status(vol, HR_VOL_ONLINE); + hr_update_vol_state(vol, HR_VOL_ONLINE); fibril_rwlock_write_unlock(&vol->states_lock); } } @@ -282,13 +282,13 @@ static void hr_raid1_ext_state_callback(hr_volume_t *vol, size_t extent, switch (rc) { case ENOMEM: - hr_update_ext_status(vol, extent, HR_EXT_INVALID); + hr_update_ext_state(vol, extent, HR_EXT_INVALID); break; case ENOENT: - hr_update_ext_status(vol, extent, HR_EXT_MISSING); + hr_update_ext_state(vol, extent, HR_EXT_MISSING); break; default: - hr_update_ext_status(vol, extent, HR_EXT_FAILED); + hr_update_ext_state(vol, extent, HR_EXT_FAILED); } hr_mark_vol_state_dirty(vol); @@ -304,8 +304,8 @@ static size_t hr_raid1_count_good_extents(hr_volume_t *vol, uint64_t ba, size_t count = 0; for (size_t i = 0; i < vol->extent_no; i++) { - if (vol->extents[i].status == HR_EXT_ONLINE || - (vol->extents[i].status == HR_EXT_REBUILD && + if (vol->extents[i].state == HR_EXT_ONLINE || + (vol->extents[i].state == HR_EXT_REBUILD && ba < rebuild_blk)) { count++; } @@ -325,7 +325,7 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, uint64_t rebuild_blk; fibril_rwlock_read_lock(&vol->states_lock); - hr_vol_status_t vol_state = vol->status; + hr_vol_state_t vol_state = vol->state; fibril_rwlock_read_unlock(&vol->states_lock); if (vol_state == HR_VOL_FAULTY || vol_state == HR_VOL_NONE) @@ -357,7 +357,7 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, for (i = 0; i < vol->extent_no; i++) { fibril_rwlock_read_lock(&vol->states_lock); - hr_ext_status_t state = vol->extents[i].status; + hr_ext_state_t state = vol->extents[i].state; fibril_rwlock_read_unlock(&vol->states_lock); if (state != HR_EXT_ONLINE && @@ -411,8 +411,8 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, } for (i = 0; i < vol->extent_no; i++) { - if (vol->extents[i].status != HR_EXT_ONLINE && - (vol->extents[i].status != HR_EXT_REBUILD || + if (vol->extents[i].state != HR_EXT_ONLINE && + (vol->extents[i].state != HR_EXT_REBUILD || ba >= rebuild_blk)) { /* * When the extent is being rebuilt, @@ -457,7 +457,7 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, end: fibril_rwlock_read_unlock(&vol->extents_lock); - hr_raid1_update_vol_status(vol); + hr_raid1_update_vol_state(vol); return rc; } @@ -532,7 +532,7 @@ static errno_t hr_raid1_rebuild(void *arg) fibril_rwlock_write_lock(&vol->states_lock); - hr_update_ext_status(vol, rebuild_idx, HR_EXT_ONLINE); + hr_update_ext_state(vol, rebuild_idx, HR_EXT_ONLINE); /* * We can be optimistic here, if some extents are @@ -540,7 +540,7 @@ static errno_t hr_raid1_rebuild(void *arg) * function will pick them up, and set the volume * state accordingly. */ - hr_update_vol_status(vol, HR_VOL_ONLINE); + hr_update_vol_state(vol, HR_VOL_ONLINE); hr_mark_vol_state_dirty(vol); fibril_rwlock_write_unlock(&vol->states_lock); @@ -557,14 +557,14 @@ static errno_t hr_raid1_rebuild(void *arg) * rebuild extent here, for now) */ fibril_rwlock_write_lock(&vol->states_lock); - hr_update_vol_status(vol, HR_VOL_DEGRADED); + hr_update_vol_state(vol, HR_VOL_DEGRADED); hr_mark_vol_state_dirty(vol); fibril_rwlock_write_unlock(&vol->states_lock); } fibril_rwlock_read_unlock(&vol->extents_lock); - hr_raid1_update_vol_status(vol); + hr_raid1_update_vol_state(vol); if (buf != NULL) free(buf); @@ -590,7 +590,7 @@ static errno_t init_rebuild(hr_volume_t *vol, size_t *rebuild_idx) size_t bad = vol->extent_no; for (size_t i = 0; i < vol->extent_no; i++) { - if (vol->extents[i].status != HR_EXT_ONLINE) { + if (vol->extents[i].state != HR_EXT_ONLINE) { bad = i; break; } @@ -605,7 +605,7 @@ static errno_t init_rebuild(hr_volume_t *vol, size_t *rebuild_idx) size_t hotspare_idx = vol->hotspare_no - 1; - hr_ext_status_t hs_state = vol->hotspares[hotspare_idx].status; + hr_ext_state_t hs_state = vol->hotspares[hotspare_idx].state; if (hs_state != HR_EXT_HOTSPARE) { HR_ERROR("hr_raid1_rebuild(): invalid hotspare state \"%s\", " "aborting rebuild\n", hr_get_ext_state_str(hs_state)); @@ -627,8 +627,8 @@ static errno_t init_rebuild(hr_volume_t *vol, size_t *rebuild_idx) atomic_store_explicit(&vol->rebuild_blk, 0, memory_order_relaxed); - hr_update_ext_status(vol, bad, HR_EXT_REBUILD); - hr_update_vol_status(vol, HR_VOL_REBUILD); + hr_update_ext_state(vol, bad, HR_EXT_REBUILD); + hr_update_vol_state(vol, HR_VOL_REBUILD); *rebuild_idx = bad; error: @@ -647,10 +647,10 @@ static errno_t swap_hs(hr_volume_t *vol, size_t bad, size_t hs) service_id_t hs_svc_id = vol->hotspares[hs].svc_id; hr_update_ext_svc_id(vol, bad, hs_svc_id); - hr_update_ext_status(vol, bad, HR_EXT_HOTSPARE); + hr_update_ext_state(vol, bad, HR_EXT_HOTSPARE); hr_update_hotspare_svc_id(vol, hs, 0); - hr_update_hotspare_status(vol, hs, HR_EXT_MISSING); + hr_update_hotspare_state(vol, hs, HR_EXT_MISSING); vol->hotspare_no--; @@ -669,16 +669,16 @@ static errno_t hr_raid1_restore_blocks(hr_volume_t *vol, size_t rebuild_idx, hr_extent_t *ext, *rebuild_ext = &vol->extents[rebuild_idx]; fibril_rwlock_read_lock(&vol->states_lock); - hr_ext_status_t rebuild_ext_status = rebuild_ext->status; + hr_ext_state_t rebuild_ext_state = rebuild_ext->state; fibril_rwlock_read_unlock(&vol->states_lock); - if (rebuild_ext_status != HR_EXT_REBUILD) + if (rebuild_ext_state != HR_EXT_REBUILD) return EINVAL; for (size_t i = 0; i < vol->extent_no; i++) { fibril_rwlock_read_lock(&vol->states_lock); ext = &vol->extents[i]; - if (ext->status != HR_EXT_ONLINE) { + if (ext->state != HR_EXT_ONLINE) { fibril_rwlock_read_unlock(&vol->states_lock); continue; } diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index cc2507ed8d..ca794b0591 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -55,7 +55,7 @@ static errno_t hr_raid5_vol_usable(hr_volume_t *); static ssize_t hr_raid5_get_bad_ext(hr_volume_t *); -static errno_t hr_raid5_update_vol_status(hr_volume_t *); +static errno_t hr_raid5_update_vol_state(hr_volume_t *); static void hr_raid5_handle_extent_error(hr_volume_t *, size_t, errno_t); static void xor(void *, const void *, size_t); static errno_t hr_raid5_read_degraded(hr_volume_t *, uint64_t, uint64_t, @@ -104,7 +104,7 @@ errno_t hr_raid5_create(hr_volume_t *new_volume) fibril_rwlock_write_lock(&new_volume->states_lock); - errno_t rc = hr_raid5_update_vol_status(new_volume); + errno_t rc = hr_raid5_update_vol_state(new_volume); if (rc != EOK) { HR_NOTE("\"%s\": unusable state, not creating\n", new_volume->devname); @@ -144,11 +144,11 @@ errno_t hr_raid5_init(hr_volume_t *vol) return EOK; } -void hr_raid5_status_event(hr_volume_t *vol) +void hr_raid5_state_event(hr_volume_t *vol) { fibril_mutex_lock(&vol->lock); fibril_rwlock_write_lock(&vol->states_lock); - (void)hr_raid5_update_vol_status(vol); + (void)hr_raid5_update_vol_state(vol); fibril_rwlock_write_unlock(&vol->states_lock); fibril_mutex_unlock(&vol->lock); } @@ -166,7 +166,7 @@ errno_t hr_raid5_add_hotspare(hr_volume_t *vol, service_id_t hotspare) /* * If the volume is degraded, start rebuild right away. */ - if (vol->status == HR_VOL_DEGRADED) { + if (vol->state == HR_VOL_DEGRADED) { HR_DEBUG("hr_raid5_add_hotspare(): volume in DEGRADED state, " "spawning new rebuild fibril\n"); fid_t fib = fibril_create(hr_raid5_rebuild, vol); @@ -242,9 +242,9 @@ static errno_t hr_raid5_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb) static errno_t hr_raid5_vol_usable(hr_volume_t *vol) { - if (vol->status == HR_VOL_ONLINE || - vol->status == HR_VOL_DEGRADED || - vol->status == HR_VOL_REBUILD) + if (vol->state == HR_VOL_ONLINE || + vol->state == HR_VOL_DEGRADED || + vol->state == HR_VOL_REBUILD) return EOK; return EIO; } @@ -256,29 +256,29 @@ static errno_t hr_raid5_vol_usable(hr_volume_t *vol) static ssize_t hr_raid5_get_bad_ext(hr_volume_t *vol) { for (size_t i = 0; i < vol->extent_no; i++) - if (vol->extents[i].status != HR_EXT_ONLINE) + if (vol->extents[i].state != HR_EXT_ONLINE) return i; return -1; } -static errno_t hr_raid5_update_vol_status(hr_volume_t *vol) +static errno_t hr_raid5_update_vol_state(hr_volume_t *vol) { - hr_vol_status_t old_state = vol->status; + hr_vol_state_t old_state = vol->state; size_t bad = 0; for (size_t i = 0; i < vol->extent_no; i++) - if (vol->extents[i].status != HR_EXT_ONLINE) + if (vol->extents[i].state != HR_EXT_ONLINE) bad++; switch (bad) { case 0: if (old_state != HR_VOL_ONLINE) - hr_update_vol_status(vol, HR_VOL_ONLINE); + hr_update_vol_state(vol, HR_VOL_ONLINE); return EOK; case 1: if (old_state != HR_VOL_DEGRADED && old_state != HR_VOL_REBUILD) { - hr_update_vol_status(vol, HR_VOL_DEGRADED); + hr_update_vol_state(vol, HR_VOL_DEGRADED); if (vol->hotspare_no > 0) { fid_t fib = fibril_create(hr_raid5_rebuild, @@ -292,7 +292,7 @@ static errno_t hr_raid5_update_vol_status(hr_volume_t *vol) return EOK; default: if (old_state != HR_VOL_FAULTY) - hr_update_vol_status(vol, HR_VOL_FAULTY); + hr_update_vol_state(vol, HR_VOL_FAULTY); return EIO; } } @@ -301,9 +301,9 @@ static void hr_raid5_handle_extent_error(hr_volume_t *vol, size_t extent, errno_t rc) { if (rc == ENOENT) - hr_update_ext_status(vol, extent, HR_EXT_MISSING); + hr_update_ext_state(vol, extent, HR_EXT_MISSING); else if (rc != EOK) - hr_update_ext_status(vol, extent, HR_EXT_FAILED); + hr_update_ext_state(vol, extent, HR_EXT_FAILED); } static void xor(void *dst, const void *src, size_t size) @@ -536,7 +536,7 @@ static errno_t hr_raid5_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, /* propagate sync */ if (type == HR_BD_SYNC && ba == 0 && cnt == 0) { hr_sync_all_extents(vol); - rc = hr_raid5_update_vol_status(vol); + rc = hr_raid5_update_vol_state(vol); return rc; } @@ -610,7 +610,7 @@ static errno_t hr_raid5_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, hr_add_ba_offset(vol, &phys_block); switch (type) { case HR_BD_SYNC: - if (vol->extents[extent].status != HR_EXT_ONLINE) + if (vol->extents[extent].state != HR_EXT_ONLINE) break; rc = block_sync_cache(vol->extents[extent].svc_id, phys_block, cnt); @@ -647,7 +647,7 @@ static errno_t hr_raid5_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, hr_raid5_handle_extent_error(vol, extent, rc); if (rc != EOK) { - rc = hr_raid5_update_vol_status(vol); + rc = hr_raid5_update_vol_state(vol); if (rc == EOK) { /* * State changed from ONLINE -> DEGRADED, @@ -699,7 +699,7 @@ static errno_t hr_raid5_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, } error: - (void)hr_raid5_update_vol_status(vol); + (void)hr_raid5_update_vol_state(vol); fibril_rwlock_write_unlock(&vol->states_lock); fibril_mutex_unlock(&vol->lock); return rc; @@ -726,7 +726,7 @@ static errno_t hr_raid5_rebuild(void *arg) size_t bad = vol->extent_no; for (size_t i = 0; i < vol->extent_no; i++) { - if (vol->extents[i].status == HR_EXT_FAILED) { + if (vol->extents[i].state == HR_EXT_FAILED) { bad = i; break; } @@ -741,7 +741,7 @@ static errno_t hr_raid5_rebuild(void *arg) size_t hotspare_idx = vol->hotspare_no - 1; - hr_ext_status_t hs_state = vol->hotspares[hotspare_idx].status; + hr_ext_state_t hs_state = vol->hotspares[hotspare_idx].state; if (hs_state != HR_EXT_HOTSPARE) { HR_ERROR("hr_raid5_rebuild(): invalid hotspare state \"%s\", " "aborting rebuild\n", hr_get_ext_state_str(hs_state)); @@ -754,11 +754,11 @@ static errno_t hr_raid5_rebuild(void *arg) block_fini(vol->extents[bad].svc_id); vol->extents[bad].svc_id = vol->hotspares[hotspare_idx].svc_id; - hr_update_ext_status(vol, bad, HR_EXT_HOTSPARE); + hr_update_ext_state(vol, bad, HR_EXT_HOTSPARE); vol->hotspares[hotspare_idx].svc_id = 0; fibril_mutex_lock(&vol->hotspare_lock); - hr_update_hotspare_status(vol, hotspare_idx, HR_EXT_MISSING); + hr_update_hotspare_state(vol, hotspare_idx, HR_EXT_MISSING); fibril_mutex_unlock(&vol->hotspare_lock); vol->hotspare_no--; @@ -768,8 +768,8 @@ static errno_t hr_raid5_rebuild(void *arg) HR_DEBUG("hr_raid5_rebuild(): starting rebuild on (%" PRIun ")\n", rebuild_ext->svc_id); - hr_update_ext_status(vol, bad, HR_EXT_REBUILD); - hr_update_vol_status(vol, HR_VOL_REBUILD); + hr_update_ext_state(vol, bad, HR_EXT_REBUILD); + hr_update_vol_state(vol, HR_VOL_REBUILD); uint64_t max_blks = DATA_XFER_LIMIT / vol->bsize; uint64_t left = vol->data_blkno / (vol->extent_no - 1); @@ -837,12 +837,12 @@ static errno_t hr_raid5_rebuild(void *arg) HR_DEBUG("hr_raid5_rebuild(): rebuild finished on \"%s\" (%" PRIun "), " "extent number %zu\n", vol->devname, vol->svc_id, hotspare_idx); - hr_update_ext_status(vol, bad, HR_EXT_ONLINE); + hr_update_ext_state(vol, bad, HR_EXT_ONLINE); rc = vol->meta_ops->save(vol, WITH_STATE_CALLBACK); end: - (void)hr_raid5_update_vol_status(vol); + (void)hr_raid5_update_vol_state(vol); fibril_rwlock_write_unlock(&vol->states_lock); fibril_rwlock_read_unlock(&vol->extents_lock); diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index b1164a11c6..3347641410 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -97,12 +97,12 @@ errno_t hr_create_vol_struct(hr_volume_t **rvol, hr_level_t level, case HR_LVL_0: vol->hr_ops.create = hr_raid0_create; vol->hr_ops.init = hr_raid0_init; - vol->hr_ops.status_event = hr_raid0_status_event; + vol->hr_ops.state_event = hr_raid0_state_event; break; case HR_LVL_1: vol->hr_ops.create = hr_raid1_create; vol->hr_ops.init = hr_raid1_init; - vol->hr_ops.status_event = hr_raid1_status_event; + vol->hr_ops.state_event = hr_raid1_state_event; if (meta_flags & HR_METADATA_HOTSPARE_SUPPORT) vol->hr_ops.add_hotspare = hr_raid1_add_hotspare; break; @@ -110,7 +110,7 @@ errno_t hr_create_vol_struct(hr_volume_t **rvol, hr_level_t level, case HR_LVL_5: vol->hr_ops.create = hr_raid5_create; vol->hr_ops.init = hr_raid5_init; - vol->hr_ops.status_event = hr_raid5_status_event; + vol->hr_ops.state_event = hr_raid5_state_event; if (meta_flags & HR_METADATA_HOTSPARE_SUPPORT) vol->hr_ops.add_hotspare = hr_raid5_add_hotspare; break; @@ -133,7 +133,7 @@ errno_t hr_create_vol_struct(hr_volume_t **rvol, hr_level_t level, goto error; } - vol->status = HR_VOL_NONE; + vol->state = HR_VOL_NONE; fibril_mutex_initialize(&vol->lock); /* XXX: will remove this */ @@ -267,7 +267,7 @@ errno_t hr_init_extents_from_cfg(hr_volume_t *vol, hr_config_t *cfg) } vol->extents[i].svc_id = svc_id; - vol->extents[i].status = HR_EXT_ONLINE; + vol->extents[i].state = HR_EXT_ONLINE; if (blkno < smallest_blkno) smallest_blkno = blkno; @@ -279,7 +279,7 @@ errno_t hr_init_extents_from_cfg(hr_volume_t *vol, hr_config_t *cfg) vol->truncated_blkno = smallest_blkno; for (i = 0; i < HR_MAX_HOTSPARES; i++) - vol->hotspares[i].status = HR_EXT_MISSING; + vol->hotspares[i].state = HR_EXT_MISSING; return EOK; @@ -373,7 +373,7 @@ void hr_add_ba_offset(hr_volume_t *vol, uint64_t *ba) *ba = *ba + vol->data_offset; } -void hr_update_ext_status(hr_volume_t *vol, size_t ext_idx, hr_ext_status_t s) +void hr_update_ext_state(hr_volume_t *vol, size_t ext_idx, hr_ext_state_t s) { if (vol->level != HR_LVL_0) assert(fibril_rwlock_is_locked(&vol->extents_lock)); @@ -382,34 +382,34 @@ void hr_update_ext_status(hr_volume_t *vol, size_t ext_idx, hr_ext_status_t s) assert(ext_idx < vol->extent_no); - hr_ext_status_t old = vol->extents[ext_idx].status; + hr_ext_state_t old = vol->extents[ext_idx].state; HR_NOTE("\"%s\": changing extent %zu state: %s -> %s\n", vol->devname, ext_idx, hr_get_ext_state_str(old), hr_get_ext_state_str(s)); - vol->extents[ext_idx].status = s; + vol->extents[ext_idx].state = s; } -void hr_update_hotspare_status(hr_volume_t *vol, size_t hs_idx, - hr_ext_status_t s) +void hr_update_hotspare_state(hr_volume_t *vol, size_t hs_idx, + hr_ext_state_t s) { assert(fibril_mutex_is_locked(&vol->hotspare_lock)); assert(hs_idx < vol->hotspare_no); - hr_ext_status_t old = vol->hotspares[hs_idx].status; + hr_ext_state_t old = vol->hotspares[hs_idx].state; HR_NOTE("\"%s\": changing hotspare %zu state: %s -> %s\n", vol->devname, hs_idx, hr_get_ext_state_str(old), hr_get_ext_state_str(s)); - vol->hotspares[hs_idx].status = s; + vol->hotspares[hs_idx].state = s; } -void hr_update_vol_status(hr_volume_t *vol, hr_vol_status_t new) +void hr_update_vol_state(hr_volume_t *vol, hr_vol_state_t new) { assert(fibril_rwlock_is_write_locked(&vol->states_lock)); HR_NOTE("\"%s\": changing volume state: %s -> %s\n", vol->devname, - hr_get_vol_state_str(vol->status), hr_get_vol_state_str(new)); - vol->status = new; + hr_get_vol_state_str(vol->state), hr_get_vol_state_str(new)); + vol->state = new; } void hr_update_ext_svc_id(hr_volume_t *vol, size_t ext_idx, service_id_t new) @@ -440,10 +440,10 @@ void hr_update_hotspare_svc_id(hr_volume_t *vol, size_t hs_idx, /* * Do a whole sync (ba = 0, cnt = 0) across all extents, - * and update extent status. *For now*, the caller has to - * update volume status after the syncs. + * and update extent state. *For now*, the caller has to + * update volume state after the syncs. * - * TODO: add update_vol_status fcn ptr for each raid + * TODO: add update_vol_state fcn ptr for each raid */ void hr_sync_all_extents(hr_volume_t *vol) { @@ -451,22 +451,22 @@ void hr_sync_all_extents(hr_volume_t *vol) fibril_mutex_lock(&vol->lock); for (size_t i = 0; i < vol->extent_no; i++) { - if (vol->extents[i].status != HR_EXT_ONLINE) + if (vol->extents[i].state != HR_EXT_ONLINE) continue; rc = block_sync_cache(vol->extents[i].svc_id, 0, 0); if (rc == ENOMEM || rc == ENOTSUP) continue; if (rc != EOK) { if (rc == ENOENT) - hr_update_ext_status(vol, i, HR_EXT_MISSING); + hr_update_ext_state(vol, i, HR_EXT_MISSING); else if (rc != EOK) - hr_update_ext_status(vol, i, HR_EXT_FAILED); + hr_update_ext_state(vol, i, HR_EXT_FAILED); } } fibril_mutex_unlock(&vol->lock); } -size_t hr_count_extents(hr_volume_t *vol, hr_ext_status_t status) +size_t hr_count_extents(hr_volume_t *vol, hr_ext_state_t state) { if (vol->level != HR_LVL_0) assert(fibril_rwlock_is_locked(&vol->extents_lock)); @@ -474,7 +474,7 @@ size_t hr_count_extents(hr_volume_t *vol, hr_ext_status_t status) size_t count = 0; for (size_t i = 0; i < vol->extent_no; i++) - if (vol->extents[i].status == status) + if (vol->extents[i].state == state) count++; return count; @@ -1051,7 +1051,7 @@ errno_t hr_util_add_hotspare(hr_volume_t *vol, service_id_t hotspare) vol->hotspare_no++; hr_update_hotspare_svc_id(vol, hs_idx, hotspare); - hr_update_hotspare_status(vol, hs_idx, HR_EXT_HOTSPARE); + hr_update_hotspare_state(vol, hs_idx, HR_EXT_HOTSPARE); hr_mark_vol_state_dirty(vol); error: diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index 87c00e3386..17851274d7 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -76,17 +76,17 @@ extern void hr_fini_devs(hr_volume_t *); extern errno_t hr_register_volume(hr_volume_t *); extern errno_t hr_check_ba_range(hr_volume_t *, size_t, uint64_t); extern void hr_add_ba_offset(hr_volume_t *, uint64_t *); -extern void hr_update_ext_status(hr_volume_t *, size_t, - hr_ext_status_t); -extern void hr_update_hotspare_status(hr_volume_t *, size_t, - hr_ext_status_t); -extern void hr_update_vol_status(hr_volume_t *, hr_vol_status_t); +extern void hr_update_ext_state(hr_volume_t *, size_t, + hr_ext_state_t); +extern void hr_update_hotspare_state(hr_volume_t *, size_t, + hr_ext_state_t); +extern void hr_update_vol_state(hr_volume_t *, hr_vol_state_t); extern void hr_update_ext_svc_id(hr_volume_t *, size_t, service_id_t); extern void hr_update_hotspare_svc_id(hr_volume_t *, size_t, service_id_t); extern void hr_sync_all_extents(hr_volume_t *); -extern size_t hr_count_extents(hr_volume_t *, hr_ext_status_t); +extern size_t hr_count_extents(hr_volume_t *, hr_ext_state_t); extern void hr_mark_vol_state_dirty(hr_volume_t *); extern void hr_range_lock_release(hr_range_lock_t *); extern hr_range_lock_t *hr_range_lock_acquire(hr_volume_t *, uint64_t, diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index 2cc768f86a..f5599f8e62 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -57,7 +57,7 @@ typedef struct hr_superblock_ops hr_superblock_ops_t; typedef struct hr_ops { errno_t (*create)(hr_volume_t *); errno_t (*init)(hr_volume_t *); - void (*status_event)(hr_volume_t *); + void (*state_event)(hr_volume_t *); errno_t (*add_hotspare)(hr_volume_t *, service_id_t); } hr_ops_t; @@ -102,7 +102,7 @@ typedef struct hr_volume { /* XXX: atomic_uint_least64_t? */ _Atomic uint64_t rebuild_blk; /* rebuild position */ _Atomic int open_cnt; /* open/close() counter */ - hr_vol_status_t status; /* volume status */ + hr_vol_state_t state; /* volume state */ void (*state_callback)(hr_volume_t *, size_t, errno_t); } hr_volume_t; @@ -135,9 +135,9 @@ extern errno_t hr_raid0_init(hr_volume_t *); extern errno_t hr_raid1_init(hr_volume_t *); extern errno_t hr_raid5_init(hr_volume_t *); -extern void hr_raid0_status_event(hr_volume_t *); -extern void hr_raid1_status_event(hr_volume_t *); -extern void hr_raid5_status_event(hr_volume_t *); +extern void hr_raid0_state_event(hr_volume_t *); +extern void hr_raid1_state_event(hr_volume_t *); +extern void hr_raid5_state_event(hr_volume_t *); extern errno_t hr_raid1_add_hotspare(hr_volume_t *, service_id_t); extern errno_t hr_raid5_add_hotspare(hr_volume_t *, service_id_t); From 964e8973d5219480170994287cdc9b715cd252a5 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Wed, 7 May 2025 14:12:18 +0200 Subject: [PATCH 214/324] hrctl: handle invalid level argument --- uspace/app/hrctl/hrctl.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index 6bfcb2e1cb..c00918a247 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -33,6 +33,7 @@ * @file */ +#include #include #include #include @@ -274,7 +275,13 @@ static int handle_create(hr_t *hr, int argc, char **argv) goto error; } - vol_config->level = strtol(argv[optind++], NULL, 10); + const char *level_str = argv[optind++]; + if (str_size(level_str) != 1 && !isdigit(level_str[0])) { + printf(NAME ": unknown level \"%s\"\n", level_str); + goto error; + } + + vol_config->level = strtol(level_str, NULL, 10); errno_t rc = fill_config_devs(argc, argv, vol_config); if (rc != EOK) From fde80323976158fdabc67da2a0a46bab9e6c97df Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Wed, 7 May 2025 14:12:36 +0200 Subject: [PATCH 215/324] hrctl: correctly handle manualy specified devices --- uspace/app/hrctl/hrctl.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index c00918a247..fc4f39dbd5 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -107,7 +107,7 @@ static errno_t fill_config_devs(int argc, char **argv, hr_config_t *cfg) errno_t rc; size_t i; - for (i = 0; i < HR_MAX_EXTENTS; i++) { + for (i = 0; i < HR_MAX_EXTENTS && optind < argc; i++) { rc = loc_service_get_id(argv[optind], &cfg->devs[i], 0); if (rc == ENOENT) { printf(NAME ": device \"%s\" not found, aborting\n", @@ -118,9 +118,7 @@ static errno_t fill_config_devs(int argc, char **argv, hr_config_t *cfg) argv[optind]); return EINVAL; } - - if (++optind >= argc) - break; + optind++; } if (optind < argc) { From ed419629bb5578c0ed24f1a04f6aad2ff3e428be Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Wed, 7 May 2025 20:38:51 +0200 Subject: [PATCH 216/324] hr: metadata/native: fix possible deadlock --- uspace/srv/bd/hr/metadata/native.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/uspace/srv/bd/hr/metadata/native.c b/uspace/srv/bd/hr/metadata/native.c index c90e1b0232..569cd52af0 100644 --- a/uspace/srv/bd/hr/metadata/native.c +++ b/uspace/srv/bd/hr/metadata/native.c @@ -378,8 +378,10 @@ static errno_t meta_native_save(hr_volume_t *vol, bool with_state_callback) fibril_rwlock_read_lock(&vol->states_lock); /* TODO: special case for REBUILD */ - if (ext->state != HR_EXT_ONLINE) + if (ext->state != HR_EXT_ONLINE) { + fibril_rwlock_read_unlock(&vol->states_lock); continue; + } fibril_rwlock_read_unlock(&vol->states_lock); From e5ea5f8b1ec2e28d8123dc8c65799ad15b065eb1 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Wed, 7 May 2025 20:54:11 +0200 Subject: [PATCH 217/324] hrctl: finalize parsing, add new sample sif config --- uspace/app/hrctl/create_file_bd_disks.bdsh | 9 + uspace/app/hrctl/hrctl.c | 361 ++++++++++++------- uspace/app/hrctl/meson.build | 4 +- uspace/app/hrctl/sample_hr_config.sif | 9 - uspace/app/hrctl/sample_hrconfig_file_bd.sif | 10 + uspace/app/hrctl/sample_hrconfig_pci.sif | 9 + 6 files changed, 256 insertions(+), 146 deletions(-) create mode 100644 uspace/app/hrctl/create_file_bd_disks.bdsh delete mode 100644 uspace/app/hrctl/sample_hr_config.sif create mode 100644 uspace/app/hrctl/sample_hrconfig_file_bd.sif create mode 100644 uspace/app/hrctl/sample_hrconfig_pci.sif diff --git a/uspace/app/hrctl/create_file_bd_disks.bdsh b/uspace/app/hrctl/create_file_bd_disks.bdsh new file mode 100644 index 0000000000..cb2d84dcfe --- /dev/null +++ b/uspace/app/hrctl/create_file_bd_disks.bdsh @@ -0,0 +1,9 @@ +mkfile -s 100M /tmp/file1 +mkfile -s 100M /tmp/file2 +mkfile -s 100M /tmp/file3 +mkfile -s 100M /tmp/file4 + +/srv/bd/file_bd -b 512 /tmp/file1 disk1 +/srv/bd/file_bd -b 512 /tmp/file2 disk2 +/srv/bd/file_bd -b 512 /tmp/file3 disk3 +/srv/bd/file_bd -b 512 /tmp/file4 disk4 diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index fc4f39dbd5..bcbab5ec43 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -49,7 +49,7 @@ static void usage(void); static errno_t fill_config_devs(int, char **, hr_config_t *); -static errno_t load_config(const char *, hr_config_t *); +static errno_t get_vol_configs_from_sif(const char *, hr_config_t **, size_t *); static const char usage_str[] = "Usage: hrctl [OPTION]...\n" @@ -93,9 +93,12 @@ static const char usage_str[] = " Simulating an extent failure with -m volume -f index is dangerous. It marks\n" " metadata as dirty in other healthy extents, and therefore invalidates\n" " the specified extent.\n" + " Nested levels have to be created manually, or from config file, but need to\n" + " be specified as separate volumes.\n" "\n" "Limitations:\n" - "\t- volume name must be shorter than 32 characters\n"; + "\t- volume name must be shorter than 32 characters\n" + "\t- automatic assembly and disassembly on nested volumes is UNDEFINED!\n"; static void usage(void) { @@ -132,172 +135,278 @@ static errno_t fill_config_devs(int argc, char **argv, hr_config_t *cfg) return EOK; } -static errno_t load_config(const char *path, hr_config_t *cfg) +static errno_t get_vol_configs_from_sif(const char *path, hr_config_t **rcfgs, + size_t *rcount) { errno_t rc; - size_t i; sif_doc_t *doc = NULL; - sif_node_t *narrays; - sif_node_t *rnode; - sif_node_t *narray; + sif_node_t *hrconfig_node; + sif_node_t *root_node; + sif_node_t *volume_node; sif_node_t *nextent; const char *ntype; const char *devname; const char *level_str; - const char *dev_no_str; const char *extent_devname; + hr_config_t *vol_configs = NULL; rc = sif_load(path, &doc); if (rc != EOK) goto error; - rnode = sif_get_root(doc); - - narrays = sif_node_first_child(rnode); - ntype = sif_node_get_type(narrays); - if (str_cmp(ntype, "arrays") != 0) { - rc = EIO; - goto error; - } - - narray = sif_node_first_child(narrays); - ntype = sif_node_get_type(narray); - if (str_cmp(ntype, "array") != 0) { - rc = EIO; - goto error; - } + root_node = sif_get_root(doc); - devname = sif_node_get_attr(narray, "devname"); - if (devname == NULL) { - rc = EIO; + hrconfig_node = sif_node_first_child(root_node); + ntype = sif_node_get_type(hrconfig_node); + if (str_cmp(ntype, "hrconfig") != 0) { + rc = EINVAL; goto error; } - str_cpy(cfg->devname, sizeof(cfg->devname), devname); - - level_str = sif_node_get_attr(narray, "level"); - if (level_str == NULL) - cfg->level = HR_LVL_UNKNOWN; - else - cfg->level = strtol(level_str, NULL, 10); - dev_no_str = sif_node_get_attr(narray, "n"); - if (dev_no_str == NULL) { - rc = EIO; - goto error; - } - cfg->dev_no = strtol(dev_no_str, NULL, 10); - - nextent = sif_node_first_child(narray); - for (i = 0; i < cfg->dev_no; i++) { - if (nextent == NULL) { + size_t vol_count = 0; + volume_node = sif_node_first_child(hrconfig_node); + while (volume_node) { + ntype = sif_node_get_type(volume_node); + if (str_cmp(ntype, "volume") != 0) { rc = EINVAL; goto error; } + vol_configs = realloc(vol_configs, + (vol_count + 1) * sizeof(hr_config_t)); + hr_config_t *cfg = vol_configs + vol_count; - ntype = sif_node_get_type(nextent); - if (str_cmp(ntype, "extent") != 0) { - rc = EIO; + devname = sif_node_get_attr(volume_node, "devname"); + if (devname == NULL) { + rc = EINVAL; goto error; } - - extent_devname = sif_node_get_attr(nextent, "devname"); - if (extent_devname == NULL) { - rc = EIO; - goto error; + str_cpy(cfg->devname, sizeof(cfg->devname), devname); + + level_str = sif_node_get_attr(volume_node, "level"); + if (level_str == NULL) + cfg->level = HR_LVL_UNKNOWN; + else + cfg->level = strtol(level_str, NULL, 10); + + nextent = sif_node_first_child(volume_node); + size_t i = 0; + while (nextent && i < HR_MAX_EXTENTS) { + ntype = sif_node_get_type(nextent); + if (str_cmp(ntype, "extent") != 0) { + rc = EINVAL; + goto error; + } + + extent_devname = sif_node_get_attr(nextent, "devname"); + if (extent_devname == NULL) { + rc = EINVAL; + goto error; + } + + rc = loc_service_get_id(extent_devname, &cfg->devs[i], 0); + if (rc == ENOENT) { + printf(NAME ": no device \"%s\", marking as missing\n", + extent_devname); + cfg->devs[i] = 0; + rc = EOK; + } else if (rc != EOK) { + printf(NAME ": error resolving device \"%s\", aborting\n", + extent_devname); + goto error; + } + + nextent = sif_node_next_child(nextent); + i++; } - rc = loc_service_get_id(extent_devname, &cfg->devs[i], 0); - if (rc == ENOENT) { - printf("hrctl: no device \"%s\", marking as missing\n", - extent_devname); - cfg->devs[i] = 0; - rc = EOK; - } else if (rc != EOK) { - printf("hrctl: error resolving device \"%s\", aborting\n", - extent_devname); - return EINVAL; + if (i > HR_MAX_EXTENTS) { + printf(NAME ": too many devices specified in volume \"%s\", " + "skipping\n", devname); + memset(&vol_configs[vol_count], 0, sizeof(hr_config_t)); + } else { + cfg->dev_no = i; + vol_count++; } - nextent = sif_node_next_child(nextent); + volume_node = sif_node_next_child(volume_node); } + if (rc == EOK) { + if (rcount) + *rcount = vol_count; + if (rcfgs) + *rcfgs = vol_configs; + } error: if (doc != NULL) sif_delete(doc); + if (rc != EOK) { + if (vol_configs) + free(vol_configs); + } return rc; } -static int handle_create(hr_t *hr, int argc, char **argv) +static int create_from_config(hr_t *hr, const char *config_path) { - if (optind >= argc) { - printf(NAME ": no arguments to --create\n"); + hr_config_t *vol_configs = NULL; + size_t vol_count = 0; + errno_t rc = get_vol_configs_from_sif(config_path, &vol_configs, + &vol_count); + if (rc != EOK) { + printf(NAME ": config parsing failed\n"); + return EXIT_FAILURE; + } + + for (size_t i = 0; i < vol_count; i++) { + rc = hr_create(hr, &vol_configs[i]); + if (rc != EOK) { + printf(NAME ": creation of volume \"%s\" failed: %s, " + "but continuing\n", + vol_configs[i].devname, str_error(rc)); + } else { + printf(NAME ": volume \"%s\" successfully created\n", + vol_configs[i].devname); + } + } + + free(vol_configs); + return EXIT_SUCCESS; +} + +static int create_from_argv(hr_t *hr, int argc, char **argv) +{ + /* we need name + --level + arg + at least one extent */ + if (optind + 3 >= argc) { + printf(NAME ": not enough arguments\n"); return EXIT_FAILURE; } hr_config_t *vol_config = calloc(1, sizeof(hr_config_t)); if (vol_config == NULL) { - printf(NAME ": not enough memory"); - return ENOMEM; + printf(NAME ": not enough memory\n"); + return EXIT_FAILURE; + } + + const char *name = argv[optind++]; + if (str_size(name) >= HR_DEVNAME_LEN) { + printf(NAME ": devname must be less then 32 bytes.\n"); + goto error; + } + + str_cpy(vol_config->devname, HR_DEVNAME_LEN, name); + + const char *level_opt = argv[optind++]; + if (str_cmp(level_opt, "--level") != 0 && + str_cmp(level_opt, "-l") != 0) { + printf(NAME ": unknown option \"%s\"\n", level_opt); + goto error; + } + + const char *level_str = argv[optind++]; + if (str_size(level_str) != 1 && !isdigit(level_str[0])) { + printf(NAME ": unknown level \"%s\"\n", level_str); + goto error; + } + + vol_config->level = strtol(level_str, NULL, 10); + + errno_t rc = fill_config_devs(argc, argv, vol_config); + if (rc != EOK) + goto error; + + rc = hr_create(hr, vol_config); + if (rc != EOK) { + printf(NAME ": creation failed: %s\n", str_error(rc)); + goto error; + } else { + printf(NAME ": volume \"%s\" successfully created\n", + vol_config->devname); + } + + free(vol_config); + return EXIT_SUCCESS; +error: + free(vol_config); + return EXIT_FAILURE; +} + +static int handle_create(hr_t *hr, int argc, char **argv) +{ + int rc; + + if (optind >= argc) { + printf(NAME ": no arguments to --create\n"); + return EXIT_FAILURE; } if (str_cmp(argv[optind], "-f") == 0) { - if (++optind >= argc) { + optind++; + if (optind >= argc) { printf(NAME ": not enough arguments\n"); - goto error; + return EXIT_FAILURE; } + const char *config_path = argv[optind++]; - errno_t rc = load_config(config_path, vol_config); - if (rc != EOK) { - printf(NAME ": config parsing failed\n"); - goto error; + + if (optind < argc) { + printf(NAME ": unexpected arguments\n"); + return EXIT_FAILURE; } + + rc = create_from_config(hr, config_path); } else { - /* we need name + --level + arg + at least one extent */ - if (optind + 3 >= argc) { - printf(NAME ": not enough arguments\n"); - goto error; - } + rc = create_from_argv(hr, argc, argv); + } - const char *name = argv[optind++]; - if (str_size(name) >= HR_DEVNAME_LEN) { - printf(NAME ": devname must be less then 32 bytes.\n"); - goto error; - } + return rc; +} - str_cpy(vol_config->devname, HR_DEVNAME_LEN, name); +static int assemble_from_config(hr_t *hr, const char *config_path) +{ + hr_config_t *vol_configs = NULL; + size_t vol_count = 0; + errno_t rc = get_vol_configs_from_sif(config_path, &vol_configs, + &vol_count); + if (rc != EOK) { + printf(NAME ": config parsing failed\n"); + return EXIT_FAILURE; + } - const char *level_opt = argv[optind++]; - if (str_cmp(level_opt, "--level") != 0 && - str_cmp(level_opt, "-l") != 0) { - printf(NAME ": unknown option \"%s\"\n", level_opt); - goto error; - } + size_t cnt = 0; + for (size_t i = 0; i < vol_count; i++) { + size_t tmpcnt = 0; + (void)hr_assemble(hr, &vol_configs[i], &tmpcnt); + cnt += tmpcnt; + } - const char *level_str = argv[optind++]; - if (str_size(level_str) != 1 && !isdigit(level_str[0])) { - printf(NAME ": unknown level \"%s\"\n", level_str); - goto error; - } + printf(NAME ": assembled %zu volumes\n", cnt); - vol_config->level = strtol(level_str, NULL, 10); + free(vol_configs); + return EXIT_SUCCESS; +} - errno_t rc = fill_config_devs(argc, argv, vol_config); - if (rc != EOK) - goto error; +static int assemble_from_argv(hr_t *hr, int argc, char **argv) +{ + hr_config_t *vol_config = calloc(1, sizeof(hr_config_t)); + if (vol_config == NULL) { + printf(NAME ": not enough memory\n"); + return ENOMEM; } - if (optind < argc) { - printf(NAME ": unexpected arguments\n"); + errno_t rc = fill_config_devs(argc, argv, vol_config); + if (rc != EOK) goto error; - } - errno_t rc = hr_create(hr, vol_config); + size_t cnt; + rc = hr_assemble(hr, vol_config, &cnt); if (rc != EOK) { - printf(NAME ": creation failed: %s\n", - str_error(rc)); + printf(NAME ": assmeble failed: %s\n", str_error(rc)); goto error; } + printf("hrctl: assembled %zu volumes\n", cnt); + free(vol_config); return EXIT_SUCCESS; error: @@ -307,6 +416,8 @@ static int handle_create(hr_t *hr, int argc, char **argv) static int handle_assemble(hr_t *hr, int argc, char **argv) { + int rc; + if (optind >= argc) { size_t cnt; errno_t rc = hr_auto_assemble(hr, &cnt); @@ -320,47 +431,24 @@ static int handle_assemble(hr_t *hr, int argc, char **argv) return EXIT_SUCCESS; } - hr_config_t *vol_config = calloc(1, sizeof(hr_config_t)); - if (vol_config == NULL) { - printf(NAME ": not enough memory"); - return ENOMEM; - } - if (str_cmp(argv[optind], "-f") == 0) { if (++optind >= argc) { printf(NAME ": not enough arguments\n"); - goto error; + return EXIT_FAILURE; } const char *config_path = argv[optind++]; - errno_t rc = load_config(config_path, vol_config); - if (rc != EOK) { - printf(NAME ": config parsing failed\n"); - goto error; - } + if (optind < argc) { printf(NAME ": unexpected arguments\n"); - goto error; + return EXIT_FAILURE; } - } else { - errno_t rc = fill_config_devs(argc, argv, vol_config); - if (rc != EOK) - goto error; - } - size_t cnt; - errno_t rc = hr_assemble(hr, vol_config, &cnt); - if (rc != EOK) { - printf(NAME ": assmeble failed: %s\n", str_error(rc)); - goto error; + rc = assemble_from_config(hr, config_path); + } else { + rc = assemble_from_argv(hr, argc, argv); } - printf("hrctl: auto assembled %zu volumes\n", cnt); - - free(vol_config); - return EXIT_SUCCESS; -error: - free(vol_config); - return EXIT_FAILURE; + return rc; } static int handle_disassemble(hr_t *hr, int argc, char **argv) @@ -463,7 +551,8 @@ int main(int argc, char **argv) goto end; } - if (hr_sess_init(&hr) != EOK) { + rc = hr_sess_init(&hr); + if (rc != EOK) { printf(NAME ": hr server session init failed: %s\n", str_error(rc)); return EXIT_FAILURE; diff --git a/uspace/app/hrctl/meson.build b/uspace/app/hrctl/meson.build index 1987e908b5..e8b21888d3 100644 --- a/uspace/app/hrctl/meson.build +++ b/uspace/app/hrctl/meson.build @@ -29,4 +29,6 @@ deps = [ 'device', 'sif' ] src = files('hrctl.c') -installed_data += { 'name': 'sample_hr_config.sif', 'dir': '/cfg' } +installed_data += { 'name': 'sample_hrconfig_pci.sif', 'dir': '/cfg' } +installed_data += { 'name': 'sample_hrconfig_file_bd.sif', 'dir': '/cfg' } +installed_data += { 'name': 'create_file_bd_disks.bdsh', 'dir': '/cfg' } diff --git a/uspace/app/hrctl/sample_hr_config.sif b/uspace/app/hrctl/sample_hr_config.sif deleted file mode 100644 index 7a48c4bcc8..0000000000 --- a/uspace/app/hrctl/sample_hr_config.sif +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/uspace/app/hrctl/sample_hrconfig_file_bd.sif b/uspace/app/hrctl/sample_hrconfig_file_bd.sif new file mode 100644 index 0000000000..36b074402a --- /dev/null +++ b/uspace/app/hrctl/sample_hrconfig_file_bd.sif @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/uspace/app/hrctl/sample_hrconfig_pci.sif b/uspace/app/hrctl/sample_hrconfig_pci.sif new file mode 100644 index 0000000000..c78f9f4a78 --- /dev/null +++ b/uspace/app/hrctl/sample_hrconfig_pci.sif @@ -0,0 +1,9 @@ + + + + + + + + + From 1cfce3fd8b46c1aafa67ebad2b6bcce1c8e684d9 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Thu, 8 May 2025 19:11:26 +0200 Subject: [PATCH 218/324] hr: raid5.c: set default layout --- uspace/srv/bd/hr/raid5.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index ca794b0591..14aa247905 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -141,6 +141,8 @@ errno_t hr_raid5_init(hr_volume_t *vol) vol->strip_size = HR_STRIP_SIZE; + vol->layout = HR_RLQ_RAID5_NR; + return EOK; } @@ -548,7 +550,7 @@ static errno_t hr_raid5_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, if (rc != EOK) return rc; - uint8_t layout = vol->layout; + hr_layout_t layout = vol->layout; hr_level_t level = vol->level; uint64_t strip_size = vol->strip_size / vol->bsize; /* in blocks */ From 2f21cd40379d7aa901196afac339b8af20502cea Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Thu, 8 May 2025 19:40:57 +0200 Subject: [PATCH 219/324] hr: util.c: fix hotspare blkno check --- uspace/srv/bd/hr/util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 3347641410..37e3e82f72 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -1037,7 +1037,7 @@ errno_t hr_util_add_hotspare(hr_volume_t *vol, service_id_t hotspare) goto error; } - if (hs_blkno - vol->meta_ops->get_size() < vol->truncated_blkno) { + if (hs_blkno < vol->truncated_blkno) { HR_ERROR("%s(): hotspare (%" PRIun ") doesn't have enough " "blocks\n", __func__, hotspare); From 00d80c6b0f31b85f1e77293e86837972a5c1f62f Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Thu, 8 May 2025 19:41:46 +0200 Subject: [PATCH 220/324] hr: raid5.c: REBUILD fix Make it work until RAID 5 rewrite is complete. --- uspace/srv/bd/hr/raid5.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 14aa247905..044b01b4be 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -830,10 +830,13 @@ static errno_t hr_raid5_rebuild(void *arg) * Let other IO requests be served * during rebuild. */ - fibril_rwlock_write_unlock(&vol->states_lock); - fibril_mutex_unlock(&vol->lock); - fibril_mutex_lock(&vol->lock); - fibril_rwlock_write_lock(&vol->states_lock); + + /* + * fibril_rwlock_write_unlock(&vol->states_lock); + * fibril_mutex_unlock(&vol->lock); + * fibril_mutex_lock(&vol->lock); + * fibril_rwlock_write_lock(&vol->states_lock); + */ } HR_DEBUG("hr_raid5_rebuild(): rebuild finished on \"%s\" (%" PRIun "), " @@ -841,8 +844,16 @@ static errno_t hr_raid5_rebuild(void *arg) hr_update_ext_state(vol, bad, HR_EXT_ONLINE); + fibril_rwlock_write_unlock(&vol->states_lock); + fibril_rwlock_read_unlock(&vol->extents_lock); + fibril_mutex_unlock(&vol->lock); + rc = vol->meta_ops->save(vol, WITH_STATE_CALLBACK); + fibril_mutex_lock(&vol->lock); + fibril_rwlock_read_lock(&vol->extents_lock); + fibril_rwlock_write_lock(&vol->states_lock); + end: (void)hr_raid5_update_vol_state(vol); From dbb1e3f7dc274c59cfbba2e347789ed231c54cf9 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Thu, 8 May 2025 19:44:04 +0200 Subject: [PATCH 221/324] hrctl: tweak configuration files --- uspace/app/hrctl/sample_hrconfig_file_bd.sif | 3 +-- uspace/app/hrctl/sample_hrconfig_pci.sif | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/uspace/app/hrctl/sample_hrconfig_file_bd.sif b/uspace/app/hrctl/sample_hrconfig_file_bd.sif index 36b074402a..c8c898a597 100644 --- a/uspace/app/hrctl/sample_hrconfig_file_bd.sif +++ b/uspace/app/hrctl/sample_hrconfig_file_bd.sif @@ -1,10 +1,9 @@ - + - diff --git a/uspace/app/hrctl/sample_hrconfig_pci.sif b/uspace/app/hrctl/sample_hrconfig_pci.sif index c78f9f4a78..74388e0285 100644 --- a/uspace/app/hrctl/sample_hrconfig_pci.sif +++ b/uspace/app/hrctl/sample_hrconfig_pci.sif @@ -1,6 +1,6 @@ - + From af73327ae2fd6fc284f0dc21012fdef8719501ee Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Thu, 8 May 2025 23:20:23 +0200 Subject: [PATCH 222/324] hr: use the term 'volume' instead of 'array' --- uspace/srv/bd/hr/hr.c | 4 ++-- uspace/srv/bd/hr/raid0.c | 2 +- uspace/srv/bd/hr/raid1.c | 2 +- uspace/srv/bd/hr/raid5.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index ea922d0790..a11201d9cb 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -114,7 +114,7 @@ static void hr_create_srv(ipc_call_t *icall) /* * If there was a missing device provided - * for creation of a new array, abort + * for creation of a new volume, abort */ for (i = 0; i < cfg->dev_no; i++) { if (cfg->devs[i] == 0) { @@ -122,7 +122,7 @@ static void hr_create_srv(ipc_call_t *icall) * XXX: own error codes, no need to log this... * its user error not service error */ - HR_ERROR("missing device provided for array " + HR_ERROR("missing device provided for volume " "creation, aborting"); free(cfg); async_answer_0(icall, EINVAL); diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index fd1478247d..3b1ad00bd9 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -87,7 +87,7 @@ errno_t hr_raid0_create(hr_volume_t *new_volume) assert(new_volume->level == HR_LVL_0); if (new_volume->extent_no < 2) { - HR_ERROR("RAID 0 array needs at least 2 devices\n"); + HR_ERROR("RAID 0 volume needs at least 2 devices\n"); return EINVAL; } diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index ce48ee8299..d76eeed003 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -97,7 +97,7 @@ errno_t hr_raid1_create(hr_volume_t *new_volume) assert(new_volume->level == HR_LVL_1); if (new_volume->extent_no < 2) { - HR_ERROR("RAID 1 array needs at least 2 devices\n"); + HR_ERROR("RAID 1 volume needs at least 2 devices\n"); return EINVAL; } diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 044b01b4be..f179636d7a 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -98,7 +98,7 @@ errno_t hr_raid5_create(hr_volume_t *new_volume) assert(new_volume->level == HR_LVL_5 || new_volume->level == HR_LVL_4); if (new_volume->extent_no < 3) { - HR_ERROR("RAID 5 array needs at least 3 devices\n"); + HR_ERROR("RAID 5 volume needs at least 3 devices\n"); return EINVAL; } From 52e405134318fe5971f2f42f4f6f0efb8a186b53 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 9 May 2025 16:18:17 +0200 Subject: [PATCH 223/324] hrctl: check realloc() return value --- uspace/app/hrctl/hrctl.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index bcbab5ec43..bb5549e0c8 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -173,6 +173,11 @@ static errno_t get_vol_configs_from_sif(const char *path, hr_config_t **rcfgs, } vol_configs = realloc(vol_configs, (vol_count + 1) * sizeof(hr_config_t)); + if (vol_configs == NULL) { + rc = ENOMEM; + goto error; + } + hr_config_t *cfg = vol_configs + vol_count; devname = sif_node_get_attr(volume_node, "devname"); From e1ed6ec05321252320e27aedd52b314da40f8b5f Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 9 May 2025 16:35:49 +0200 Subject: [PATCH 224/324] hr: auto assembly: detect bogus label type --- uspace/srv/bd/hr/util.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 37e3e82f72..f3c588c3e4 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -656,12 +656,7 @@ static errno_t hr_fill_disk_part_svcs_list(list_t *list) if (rc != EOK) goto error; - if (disk_info.ltype == lt_none) { - rc = hr_add_svc_linked_to_list(list, disk_svcs[i], - false, NULL); - if (rc != EOK) - goto error; - } else { + if (disk_info.ltype != lt_none) { size_t part_count; service_id_t *part_ids = NULL; rc = vbd_label_get_parts(vbd, disk_svcs[i], &part_ids, @@ -687,6 +682,24 @@ static errno_t hr_fill_disk_part_svcs_list(list_t *list) } free(part_ids); + + /* + * vbd can detect some bogus label type, but + * no partitions. In that case we handle the + * svc_id as a label-less disk. + * + * This can happen when creating an exfat fs + * in FreeBSD for example. + */ + if (part_count == 0) + disk_info.ltype = lt_none; + } + + if (disk_info.ltype == lt_none) { + rc = hr_add_svc_linked_to_list(list, disk_svcs[i], + false, NULL); + if (rc != EOK) + goto error; } } From 7e68d617f75ad0794d7df3a97b0c5d5e752275cf Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 9 May 2025 16:36:55 +0200 Subject: [PATCH 225/324] hr: metadata/geom/stripe: don't dump in vol init --- uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c index c3e0088ee0..669981584a 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c @@ -127,8 +127,6 @@ static errno_t meta_gstripe_init_meta2vol(const list_t *list, hr_volume_t *vol) list_foreach(*list, link, struct dev_list_member, iter) { struct g_stripe_metadata *iter_meta = iter->md; - meta_gstripe_dump(iter_meta); - if (iter_meta->md_provsize < smallest_provider_size) { smallest_provider_size = iter_meta->md_provsize; main_meta = iter_meta; From bfe4a88baa77ec9bf31d834a0ba65b4576ee4963 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sat, 10 May 2025 16:07:54 +0200 Subject: [PATCH 226/324] bdwrite: measure and print elapsed time --- uspace/app/bdwrite/bdwrite.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/uspace/app/bdwrite/bdwrite.c b/uspace/app/bdwrite/bdwrite.c index 5294e94dbe..a2d523bec1 100644 --- a/uspace/app/bdwrite/bdwrite.c +++ b/uspace/app/bdwrite/bdwrite.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Miroslav Cimerman + * Copyright (c) 2025 Miroslav Cimerman * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -40,6 +40,7 @@ #include #include #include +#include static void usage(void); @@ -112,6 +113,11 @@ int main(int argc, char **argv) rc = ENOMEM; goto end; } + + stopwatch_t stopwatch; + stopwatch_init(&stopwatch); + stopwatch_start(&stopwatch); + uint64_t left = blkcnt; while (left != 0) { uint64_t blks_to_write = min(to_alloc / bsize, left); @@ -130,6 +136,11 @@ int main(int argc, char **argv) off += blks_to_write; } end: + stopwatch_stop(&stopwatch); + nsec_t t = stopwatch_get_nanos(&stopwatch); + printf("Elapsed time:\n"); + printf("\t%llu ms\n", NSEC2MSEC(t)); + printf("\t%lf s\n", NSEC2SEC((double)t)); free(buf); block_fini(dev); return rc; From 287b2ea87c74732fac0422243087e01c8507f5ae Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Thu, 15 May 2025 20:27:50 +0200 Subject: [PATCH 227/324] hr: don't add "devices/" prefix on vol registration --- uspace/srv/bd/hr/util.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index f3c588c3e4..6928014cc7 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -323,17 +323,12 @@ errno_t hr_register_volume(hr_volume_t *vol) errno_t rc; service_id_t new_id; category_id_t cat_id; - char *fullname = NULL; - char *devname = vol->devname; + const char *devname = vol->devname; - if (asprintf(&fullname, "devices/%s", devname) < 0) - return ENOMEM; - - rc = loc_service_register(hr_srv, fullname, &new_id); + rc = loc_service_register(hr_srv, devname, &new_id); if (rc != EOK) { HR_ERROR("unable to register device \"%s\": %s\n", - fullname, str_error(rc)); - free(fullname); + devname, str_error(rc)); return rc; } @@ -347,17 +342,14 @@ errno_t hr_register_volume(hr_volume_t *vol) rc = loc_service_add_to_cat(hr_srv, new_id, cat_id); if (rc != EOK) { HR_ERROR("failed adding \"%s\" to category \"raid\": %s\n", - fullname, str_error(rc)); + devname, str_error(rc)); goto error; } vol->svc_id = new_id; - - free(fullname); return EOK; error: rc = loc_service_unregister(hr_srv, new_id); - free(fullname); return rc; } From 9a3eec11c53dc88b39ba77db4f3c6c37bdb41da9 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Thu, 15 May 2025 21:23:42 +0200 Subject: [PATCH 228/324] hr: util: hr_get_volume_svcs() --- uspace/srv/bd/hr/util.c | 29 +++++++++++++++++++++++++++++ uspace/srv/bd/hr/util.h | 1 + 2 files changed, 30 insertions(+) diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 6928014cc7..7f5c069b25 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -172,6 +172,35 @@ void hr_destroy_vol_struct(hr_volume_t *vol) free(vol); } +errno_t hr_get_volume_svcs(size_t *rcnt, service_id_t **rsvcs) +{ + size_t i; + service_id_t *vol_svcs; + + if (rcnt == NULL || rsvcs == NULL) + return EINVAL; + + fibril_rwlock_read_lock(&hr_volumes_lock); + + size_t vol_cnt = list_count(&hr_volumes); + vol_svcs = malloc(vol_cnt * sizeof(service_id_t)); + if (vol_svcs == NULL) { + fibril_rwlock_read_unlock(&hr_volumes_lock); + return ENOMEM; + } + + i = 0; + list_foreach(hr_volumes, lvolumes, hr_volume_t, iter) + vol_svcs[i++] = iter->svc_id; + + fibril_rwlock_read_unlock(&hr_volumes_lock); + + *rcnt = vol_cnt; + *rsvcs = vol_svcs; + + return EOK; +} + hr_volume_t *hr_get_volume(service_id_t svc_id) { HR_DEBUG("%s()", __func__); diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index 17851274d7..da592e4d56 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -69,6 +69,7 @@ struct dev_list_member { extern errno_t hr_create_vol_struct(hr_volume_t **, hr_level_t, const char *, hr_metadata_type_t); extern void hr_destroy_vol_struct(hr_volume_t *); +extern errno_t hr_get_volume_svcs(size_t *, service_id_t **); extern hr_volume_t *hr_get_volume(service_id_t); extern errno_t hr_remove_volume(hr_volume_t *); extern errno_t hr_init_extents_from_cfg(hr_volume_t *, hr_config_t *); From c9ce6d22ba355a1d4bee6ddcf413df7f7a86db77 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Thu, 15 May 2025 21:24:51 +0200 Subject: [PATCH 229/324] hr: refactor volume removal --- uspace/srv/bd/hr/hr.c | 31 +++++++++++-------------------- uspace/srv/bd/hr/util.c | 11 +++++++---- uspace/srv/bd/hr/util.h | 2 +- 3 files changed, 19 insertions(+), 25 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index a11201d9cb..45a3dacce3 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -295,17 +295,10 @@ static void hr_stop_srv(ipc_call_t *icall) errno_t rc = EOK; service_id_t svc_id; - hr_volume_t *vol; svc_id = ipc_get_arg1(icall); - vol = hr_get_volume(svc_id); - if (vol == NULL) { - async_answer_0(icall, ENOENT); - return; - } - - rc = hr_remove_volume(vol); + rc = hr_remove_volume(svc_id); async_answer_0(icall, rc); } @@ -318,25 +311,23 @@ static void hr_stop_all_srv(ipc_call_t *icall) { HR_DEBUG("%s()", __func__); - hr_volume_t *vol; + service_id_t *vol_svcs = NULL; errno_t rc = EOK; + size_t i, vol_cnt; - while (true) { - fibril_rwlock_write_lock(&hr_volumes_lock); - if (list_empty(&hr_volumes)) { - fibril_rwlock_write_unlock(&hr_volumes_lock); - break; - } - - vol = list_pop(&hr_volumes, hr_volume_t, lvolumes); - - fibril_rwlock_write_unlock(&hr_volumes_lock); + rc = hr_get_volume_svcs(&vol_cnt, &vol_svcs); + if (rc != EOK) + goto fail; - rc = hr_remove_volume(vol); + for (i = 0; i < vol_cnt; i++) { + rc = hr_remove_volume(vol_svcs[i]); if (rc != EOK) break; } +fail: + if (vol_svcs != NULL) + free(vol_svcs); async_answer_0(icall, rc); } diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 7f5c069b25..08a526bf58 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -214,19 +214,24 @@ hr_volume_t *hr_get_volume(service_id_t svc_id) break; } } - fibril_rwlock_read_unlock(&hr_volumes_lock); + return rvol; } -errno_t hr_remove_volume(hr_volume_t *vol) +errno_t hr_remove_volume(service_id_t svc_id) { HR_DEBUG("%s()", __func__); + hr_volume_t *vol = hr_get_volume(svc_id); + if (vol == NULL) + return ENOENT; + fibril_rwlock_write_lock(&hr_volumes_lock); int open_cnt = atomic_load_explicit(&vol->open_cnt, memory_order_relaxed); + /* * The atomicity of this if condition (and this whole * operation) is provided by the write lock - no new @@ -246,8 +251,6 @@ errno_t hr_remove_volume(hr_volume_t *vol) /* save metadata, but we don't care about states anymore */ (void)vol->meta_ops->save(vol, NO_STATE_CALLBACK); - service_id_t svc_id = vol->svc_id; - HR_NOTE("deactivating volume \"%s\"\n", vol->devname); hr_destroy_vol_struct(vol); diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index da592e4d56..8746af345d 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -71,7 +71,7 @@ extern errno_t hr_create_vol_struct(hr_volume_t **, hr_level_t, extern void hr_destroy_vol_struct(hr_volume_t *); extern errno_t hr_get_volume_svcs(size_t *, service_id_t **); extern hr_volume_t *hr_get_volume(service_id_t); -extern errno_t hr_remove_volume(hr_volume_t *); +extern errno_t hr_remove_volume(service_id_t); extern errno_t hr_init_extents_from_cfg(hr_volume_t *, hr_config_t *); extern void hr_fini_devs(hr_volume_t *); extern errno_t hr_register_volume(hr_volume_t *); From a2281efcbc37a47301c66085d8dbb707e71b2171 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sat, 17 May 2025 13:35:38 +0200 Subject: [PATCH 230/324] hr: print service id of created volume --- uspace/srv/bd/hr/hr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 45a3dacce3..3da9446c35 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -166,7 +166,7 @@ static void hr_create_srv(ipc_call_t *icall) list_append(&vol->lvolumes, &hr_volumes); fibril_rwlock_write_unlock(&hr_volumes_lock); - HR_NOTE("created volume \"%s\"\n", vol->devname); + HR_NOTE("created volume \"%s\" (%lu)\n", vol->devname, vol->svc_id); free(cfg); async_answer_0(icall, rc); From 6f132576633ab217899555a6ecd65a172fab6f54 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 20 May 2025 12:55:15 +0200 Subject: [PATCH 231/324] hr: cstyle: don't align struct members and fcn decls --- uspace/app/hrctl/hrctl.c | 4 +- uspace/lib/device/include/hr.h | 104 ++++++++--------- uspace/srv/bd/hr/fge.c | 76 ++++++------ uspace/srv/bd/hr/fge.h | 12 +- uspace/srv/bd/hr/io.h | 14 +-- .../bd/hr/metadata/foreign/geom/hr_g_mirror.c | 71 ++++++----- .../bd/hr/metadata/foreign/geom/hr_g_stripe.c | 73 ++++++------ .../metadata/foreign/softraid/hr_softraid.c | 73 ++++++------ uspace/srv/bd/hr/metadata/native.c | 71 ++++++----- uspace/srv/bd/hr/metadata/native.h | 40 +++---- uspace/srv/bd/hr/raid0.c | 34 +++--- uspace/srv/bd/hr/raid1.c | 44 +++---- uspace/srv/bd/hr/raid5.c | 49 ++++---- uspace/srv/bd/hr/superblock.h | 36 +++--- uspace/srv/bd/hr/util.c | 22 ++-- uspace/srv/bd/hr/util.h | 63 +++++----- uspace/srv/bd/hr/var.h | 110 +++++++++--------- 17 files changed, 443 insertions(+), 453 deletions(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index bb5549e0c8..4f55107cdd 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -47,8 +47,8 @@ #define NAME "hrctl" -static void usage(void); -static errno_t fill_config_devs(int, char **, hr_config_t *); +static void usage(void); +static errno_t fill_config_devs(int, char **, hr_config_t *); static errno_t get_vol_configs_from_sif(const char *, hr_config_t **, size_t *); static const char usage_str[] = diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index 140501f048..338eb2159d 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -47,35 +47,35 @@ #define HR_DEVNAME_LEN 32 typedef enum hr_level { - HR_LVL_0 = 0x00, /* striping, no redundancy */ - HR_LVL_1 = 0x01, /* n-way mirroring */ - HR_LVL_4 = 0x04, /* dedicated parity */ - HR_LVL_5 = 0x05, /* distributed parity */ - HR_LVL_UNKNOWN = 0xFF + HR_LVL_0 = 0x00, /* striping, no redundancy */ + HR_LVL_1 = 0x01, /* n-way mirroring */ + HR_LVL_4 = 0x04, /* dedicated parity */ + HR_LVL_5 = 0x05, /* distributed parity */ + HR_LVL_UNKNOWN = 0xFF } hr_level_t; typedef enum hr_layout { - HR_RLQ_NONE = 0, - HR_RLQ_RAID4_0, /* RAID-4 Non-Rotating Parity 0 */ - HR_RLQ_RAID4_N, /* RAID-4 Non-Rotating Parity N */ - HR_RLQ_RAID5_0R, /* RAID-5 Rotating Parity 0 with Data Restart */ - HR_RLQ_RAID5_NR, /* RAID-5 Rotating Parity N with Data Restart */ - HR_RLQ_RAID5_NC /* RAID-5 Rotating Parity N with Data Continuation */ + HR_RLQ_NONE = 0, + HR_RLQ_RAID4_0, /* RAID-4 Non-Rotating Parity 0 */ + HR_RLQ_RAID4_N, /* RAID-4 Non-Rotating Parity N */ + HR_RLQ_RAID5_0R, /* RAID-5 Rotating Parity 0 with Data Restart */ + HR_RLQ_RAID5_NR, /* RAID-5 Rotating Parity N with Data Restart */ + HR_RLQ_RAID5_NC /* RAID-5 Rotating Parity N with Data Continuation */ } hr_layout_t; typedef enum hr_vol_state { - HR_VOL_NONE = 0, /* Unknown/None */ - HR_VOL_ONLINE, /* optimal */ - HR_VOL_FAULTY, /* unusable */ - HR_VOL_DEGRADED, /* not optimal */ - HR_VOL_REBUILD /* rebuild in progress */ + HR_VOL_NONE = 0, /* Unknown/None */ + HR_VOL_ONLINE, /* optimal */ + HR_VOL_FAULTY, /* unusable */ + HR_VOL_DEGRADED, /* not optimal */ + HR_VOL_REBUILD /* rebuild in progress */ } hr_vol_state_t; typedef enum hr_ext_state { - HR_EXT_NONE = 0, /* unknown/none state */ - HR_EXT_INVALID, /* working but not consistent */ - HR_EXT_ONLINE, /* ok */ - HR_EXT_MISSING, /* offline */ + HR_EXT_NONE = 0, /* unknown/none state */ + HR_EXT_INVALID, /* working but not consistent */ + HR_EXT_ONLINE, /* ok */ + HR_EXT_MISSING, /* offline */ HR_EXT_FAILED, HR_EXT_REBUILD, HR_EXT_HOTSPARE @@ -86,53 +86,53 @@ typedef struct hr { } hr_t; typedef struct hr_config { - char devname[HR_DEVNAME_LEN]; - service_id_t devs[HR_MAX_EXTENTS]; - size_t dev_no; - hr_level_t level; + char devname[HR_DEVNAME_LEN]; + service_id_t devs[HR_MAX_EXTENTS]; + size_t dev_no; + hr_level_t level; } hr_config_t; typedef struct hr_extent { - service_id_t svc_id; - hr_ext_state_t state; + service_id_t svc_id; + hr_ext_state_t state; } hr_extent_t; typedef struct hr_vol_info { - hr_extent_t extents[HR_MAX_EXTENTS]; - hr_extent_t hotspares[HR_MAX_HOTSPARES]; - size_t extent_no; - size_t hotspare_no; - service_id_t svc_id; - hr_level_t level; - uint64_t nblocks; - uint32_t strip_size; - size_t bsize; - hr_vol_state_t state; - uint8_t layout; + hr_extent_t extents[HR_MAX_EXTENTS]; + hr_extent_t hotspares[HR_MAX_HOTSPARES]; + size_t extent_no; + size_t hotspare_no; + service_id_t svc_id; + hr_level_t level; + uint64_t nblocks; + uint32_t strip_size; + size_t bsize; + hr_vol_state_t state; + uint8_t layout; } hr_vol_info_t; typedef enum { - HR_METADATA_NATIVE = 0, + HR_METADATA_NATIVE = 0, HR_METADATA_GEOM_MIRROR, HR_METADATA_GEOM_STRIPE, HR_METADATA_SOFTRAID, HR_METADATA_LAST_DUMMY } hr_metadata_type_t; -extern errno_t hr_sess_init(hr_t **); -extern void hr_sess_destroy(hr_t *); -extern errno_t hr_create(hr_t *, hr_config_t *); -extern errno_t hr_assemble(hr_t *, hr_config_t *, size_t *); -extern errno_t hr_auto_assemble(hr_t *, size_t *); -extern errno_t hr_stop(hr_t *, const char *); -extern errno_t hr_stop_all(hr_t *); -extern errno_t hr_fail_extent(hr_t *, const char *, unsigned long); -extern errno_t hr_add_hotspare(hr_t *, const char *, const char *); -extern errno_t hr_print_state(hr_t *); -extern const char *hr_get_vol_state_str(hr_vol_state_t); -extern const char *hr_get_ext_state_str(hr_ext_state_t); -extern const char *hr_get_layout_str(hr_layout_t); -extern const char *hr_get_metadata_type_str(hr_metadata_type_t); +extern errno_t hr_sess_init(hr_t **); +extern void hr_sess_destroy(hr_t *); +extern errno_t hr_create(hr_t *, hr_config_t *); +extern errno_t hr_assemble(hr_t *, hr_config_t *, size_t *); +extern errno_t hr_auto_assemble(hr_t *, size_t *); +extern errno_t hr_stop(hr_t *, const char *); +extern errno_t hr_stop_all(hr_t *); +extern errno_t hr_fail_extent(hr_t *, const char *, unsigned long); +extern errno_t hr_add_hotspare(hr_t *, const char *, const char *); +extern errno_t hr_print_state(hr_t *); +extern const char *hr_get_vol_state_str(hr_vol_state_t); +extern const char *hr_get_ext_state_str(hr_ext_state_t); +extern const char *hr_get_layout_str(hr_layout_t); +extern const char *hr_get_metadata_type_str(hr_metadata_type_t); #endif diff --git a/uspace/srv/bd/hr/fge.c b/uspace/srv/bd/hr/fge.c index 7d4ad94099..1eafc67c98 100644 --- a/uspace/srv/bd/hr/fge.c +++ b/uspace/srv/bd/hr/fge.c @@ -58,57 +58,57 @@ typedef struct fge_fibril_data fge_fibril_data_t; struct wu_queue; typedef struct wu_queue wu_queue_t; -static void *hr_fpool_make_storage(hr_fpool_t *, ssize_t *); -static void hr_fpool_group_epilogue(hr_fpool_t *); -static errno_t fge_fibril(void *); -static errno_t wu_queue_init(wu_queue_t *, size_t); -static void wu_queue_push(wu_queue_t *, fge_fibril_data_t *); -static void wu_queue_pop(wu_queue_t *, fge_fibril_data_t *); -static ssize_t hr_fpool_get_free_slot(hr_fpool_t *); +static void *hr_fpool_make_storage(hr_fpool_t *, ssize_t *); +static void hr_fpool_group_epilogue(hr_fpool_t *); +static errno_t fge_fibril(void *); +static errno_t wu_queue_init(wu_queue_t *, size_t); +static void wu_queue_push(wu_queue_t *, fge_fibril_data_t *); +static void wu_queue_pop(wu_queue_t *, fge_fibril_data_t *); +static ssize_t hr_fpool_get_free_slot(hr_fpool_t *); struct fge_fibril_data { - hr_wu_t wu; /* work unit function pointer */ - void *arg; /* work unit function argument */ - hr_fgroup_t *group; /* back-pointer to group */ - ssize_t memslot; /* index to pool bitmap slot */ + hr_wu_t wu; /* work unit function pointer */ + void *arg; /* work unit function argument */ + hr_fgroup_t *group; /* back-pointer to group */ + ssize_t memslot; /* index to pool bitmap slot */ }; struct wu_queue { - fibril_mutex_t lock; - fibril_condvar_t not_empty; - fibril_condvar_t not_full; - fge_fibril_data_t *fexecs; /* circ-buf memory */ + fibril_mutex_t lock; + fibril_condvar_t not_empty; + fibril_condvar_t not_full; + fge_fibril_data_t *fexecs; /* circ-buf memory */ circ_buf_t cbuf; }; struct hr_fpool { - fibril_mutex_t lock; - bitmap_t bitmap; /* memory slot bitmap */ - wu_queue_t queue; - fid_t *fibrils; - uint8_t *wu_storage; /* pre-allocated pool storage */ - size_t fibril_cnt; - size_t max_wus; - size_t active_groups; - bool stop; - size_t wu_size; - size_t wu_storage_free_count; + fibril_mutex_t lock; + bitmap_t bitmap; /* memory slot bitmap */ + wu_queue_t queue; + fid_t *fibrils; + uint8_t *wu_storage; /* pre-allocated pool storage */ + size_t fibril_cnt; + size_t max_wus; + size_t active_groups; + bool stop; + size_t wu_size; + size_t wu_storage_free_count; fibril_condvar_t all_wus_done; }; struct hr_fgroup { - hr_fpool_t *pool; /* back-pointer to pool */ - size_t wu_cnt; /* upper bound of work units */ - size_t submitted; /* number of submitted jobs */ - size_t reserved_cnt; /* no. of reserved wu storage slots */ - size_t reserved_avail; - size_t *memslots; /* indices to pool bitmap */ - void *own_mem; /* own allocated memory */ - size_t own_used; /* own memory slots used counter */ - errno_t final_errno; /* agreggated errno */ - size_t finished_okay; /* no. of wus that ended with EOK */ - size_t finished_fail; /* no. of wus that ended with != EOK */ - fibril_mutex_t lock; + hr_fpool_t *pool;/* back-pointer to pool */ + size_t wu_cnt;/* upper bound of work units */ + size_t submitted; /* number of submitted jobs */ + size_t reserved_cnt; /* no. of reserved wu storage slots */ + size_t reserved_avail; + size_t *memslots; /* indices to pool bitmap */ + void *own_mem; /* own allocated memory */ + size_t own_used; /* own memory slots used counter */ + errno_t final_errno; /* agreggated errno */ + size_t finished_okay; /* no. of wus that ended with EOK */ + size_t finished_fail; /* no. of wus that ended with != EOK */ + fibril_mutex_t lock; fibril_condvar_t all_done; }; diff --git a/uspace/srv/bd/hr/fge.h b/uspace/srv/bd/hr/fge.h index 1deca8743f..fb433e3a78 100644 --- a/uspace/srv/bd/hr/fge.h +++ b/uspace/srv/bd/hr/fge.h @@ -47,12 +47,12 @@ typedef struct hr_fgroup hr_fgroup_t; typedef errno_t (*hr_wu_t)(void *); -extern hr_fpool_t *hr_fpool_create(size_t, size_t, size_t); -extern void hr_fpool_destroy(hr_fpool_t *); -extern hr_fgroup_t *hr_fgroup_create(hr_fpool_t *, size_t); -extern void *hr_fgroup_alloc(hr_fgroup_t *); -extern void hr_fgroup_submit(hr_fgroup_t *, hr_wu_t, void *); -extern errno_t hr_fgroup_wait(hr_fgroup_t *, size_t *, size_t *); +extern hr_fpool_t *hr_fpool_create(size_t, size_t, size_t); +extern void hr_fpool_destroy(hr_fpool_t *); +extern hr_fgroup_t *hr_fgroup_create(hr_fpool_t *, size_t); +extern void *hr_fgroup_alloc(hr_fgroup_t *); +extern void hr_fgroup_submit(hr_fgroup_t *, hr_wu_t, void *); +extern errno_t hr_fgroup_wait(hr_fgroup_t *, size_t *, size_t *); #endif diff --git a/uspace/srv/bd/hr/io.h b/uspace/srv/bd/hr/io.h index 9e8128b7f6..48076b5643 100644 --- a/uspace/srv/bd/hr/io.h +++ b/uspace/srv/bd/hr/io.h @@ -39,13 +39,13 @@ #include "var.h" typedef struct hr_io { - hr_bd_op_type_t type; - uint64_t ba; - uint64_t cnt; - size_t extent; - void *data_read; - const void *data_write; - hr_volume_t *vol; + hr_bd_op_type_t type; + uint64_t ba; + uint64_t cnt; + size_t extent; + void *data_read; + const void *data_write; + hr_volume_t *vol; } hr_io_t; errno_t hr_io_worker(void *); diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c index e186395c1d..5dff4237a5 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c @@ -52,45 +52,44 @@ #include "g_mirror.h" -static void *meta_gmirror_alloc_struct(void); -static errno_t meta_gmirror_init_vol2meta(const hr_volume_t *, void *); -static errno_t meta_gmirror_init_meta2vol(const list_t *, - hr_volume_t *); -static void meta_gmirror_encode(void *, void *); -static errno_t meta_gmirror_decode(const void *, void *); -static errno_t meta_gmirror_get_block(service_id_t, void **); -static errno_t meta_gmirror_write_block(service_id_t, const void *); -static bool meta_gmirror_has_valid_magic(const void *); -static bool meta_gmirror_compare_uuids(const void *, const void *); -static void meta_gmirror_inc_counter(void *); -static errno_t meta_gmirror_save(hr_volume_t *, bool); -static const char *meta_gmirror_get_devname(const void *); -static hr_level_t meta_gmirror_get_level(const void *); -static uint64_t meta_gmirror_get_data_offset(void); -static size_t meta_gmirror_get_size(void); -static uint8_t meta_gmirror_get_flags(void); +static void *meta_gmirror_alloc_struct(void); +static errno_t meta_gmirror_init_vol2meta(const hr_volume_t *, void *); +static errno_t meta_gmirror_init_meta2vol(const list_t *, hr_volume_t *); +static void meta_gmirror_encode(void *, void *); +static errno_t meta_gmirror_decode(const void *, void *); +static errno_t meta_gmirror_get_block(service_id_t, void **); +static errno_t meta_gmirror_write_block(service_id_t, const void *); +static bool meta_gmirror_has_valid_magic(const void *); +static bool meta_gmirror_compare_uuids(const void *, const void *); +static void meta_gmirror_inc_counter(void *); +static errno_t meta_gmirror_save(hr_volume_t *, bool); +static const char *meta_gmirror_get_devname(const void *); +static hr_level_t meta_gmirror_get_level(const void *); +static uint64_t meta_gmirror_get_data_offset(void); +static size_t meta_gmirror_get_size(void); +static uint8_t meta_gmirror_get_flags(void); static hr_metadata_type_t meta_gmirror_get_type(void); -static void meta_gmirror_dump(const void *); +static void meta_gmirror_dump(const void *); hr_superblock_ops_t metadata_gmirror_ops = { - .alloc_struct = meta_gmirror_alloc_struct, - .init_vol2meta = meta_gmirror_init_vol2meta, - .init_meta2vol = meta_gmirror_init_meta2vol, - .encode = meta_gmirror_encode, - .decode = meta_gmirror_decode, - .get_block = meta_gmirror_get_block, - .write_block = meta_gmirror_write_block, - .has_valid_magic = meta_gmirror_has_valid_magic, - .compare_uuids = meta_gmirror_compare_uuids, - .inc_counter = meta_gmirror_inc_counter, - .save = meta_gmirror_save, - .get_devname = meta_gmirror_get_devname, - .get_level = meta_gmirror_get_level, - .get_data_offset = meta_gmirror_get_data_offset, - .get_size = meta_gmirror_get_size, - .get_flags = meta_gmirror_get_flags, - .get_type = meta_gmirror_get_type, - .dump = meta_gmirror_dump + .alloc_struct = meta_gmirror_alloc_struct, + .init_vol2meta = meta_gmirror_init_vol2meta, + .init_meta2vol = meta_gmirror_init_meta2vol, + .encode = meta_gmirror_encode, + .decode = meta_gmirror_decode, + .get_block = meta_gmirror_get_block, + .write_block = meta_gmirror_write_block, + .has_valid_magic = meta_gmirror_has_valid_magic, + .compare_uuids = meta_gmirror_compare_uuids, + .inc_counter = meta_gmirror_inc_counter, + .save = meta_gmirror_save, + .get_devname = meta_gmirror_get_devname, + .get_level = meta_gmirror_get_level, + .get_data_offset = meta_gmirror_get_data_offset, + .get_size = meta_gmirror_get_size, + .get_flags = meta_gmirror_get_flags, + .get_type = meta_gmirror_get_type, + .dump = meta_gmirror_dump }; static void *meta_gmirror_alloc_struct(void) diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c index 669981584a..65990d5979 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c @@ -52,45 +52,44 @@ #include "g_stripe.h" -static void *meta_gstripe_alloc_struct(void); -static errno_t meta_gstripe_init_vol2meta(const hr_volume_t *, void *); -static errno_t meta_gstripe_init_meta2vol(const list_t *, - hr_volume_t *); -static void meta_gstripe_encode(void *, void *); -static errno_t meta_gstripe_decode(const void *, void *); -static errno_t meta_gstripe_get_block(service_id_t, void **); -static errno_t meta_gstripe_write_block(service_id_t, const void *); -static bool meta_gstripe_has_valid_magic(const void *); -static bool meta_gstripe_compare_uuids(const void *, const void *); -static void meta_gstripe_inc_counter(void *); -static errno_t meta_gstripe_save(hr_volume_t *, bool); -static const char *meta_gstripe_get_devname(const void *); -static hr_level_t meta_gstripe_get_level(const void *); -static uint64_t meta_gstripe_get_data_offset(void); -static size_t meta_gstripe_get_size(void); -static uint8_t meta_gstripe_get_flags(void); -static hr_metadata_type_t meta_gstripe_get_type(void); -static void meta_gstripe_dump(const void *); +static void *meta_gstripe_alloc_struct(void); +static errno_t meta_gstripe_init_vol2meta(const hr_volume_t *, void *); +static errno_t meta_gstripe_init_meta2vol(const list_t *, hr_volume_t *); +static void meta_gstripe_encode(void *, void *); +static errno_t meta_gstripe_decode(const void *, void *); +static errno_t meta_gstripe_get_block(service_id_t, void **); +static errno_t meta_gstripe_write_block(service_id_t, const void *); +static bool meta_gstripe_has_valid_magic(const void *); +static bool meta_gstripe_compare_uuids(const void *, const void *); +static void meta_gstripe_inc_counter(void *); +static errno_t meta_gstripe_save(hr_volume_t *, bool); +static const char *meta_gstripe_get_devname(const void *); +static hr_level_t meta_gstripe_get_level(const void *); +static uint64_t meta_gstripe_get_data_offset(void); +static size_t meta_gstripe_get_size(void); +static uint8_t meta_gstripe_get_flags(void); +static hr_metadata_type_t meta_gstripe_get_type(void); +static void meta_gstripe_dump(const void *); hr_superblock_ops_t metadata_gstripe_ops = { - .alloc_struct = meta_gstripe_alloc_struct, - .init_vol2meta = meta_gstripe_init_vol2meta, - .init_meta2vol = meta_gstripe_init_meta2vol, - .encode = meta_gstripe_encode, - .decode = meta_gstripe_decode, - .get_block = meta_gstripe_get_block, - .write_block = meta_gstripe_write_block, - .has_valid_magic = meta_gstripe_has_valid_magic, - .compare_uuids = meta_gstripe_compare_uuids, - .inc_counter = meta_gstripe_inc_counter, - .save = meta_gstripe_save, - .get_devname = meta_gstripe_get_devname, - .get_level = meta_gstripe_get_level, - .get_data_offset = meta_gstripe_get_data_offset, - .get_size = meta_gstripe_get_size, - .get_flags = meta_gstripe_get_flags, - .get_type = meta_gstripe_get_type, - .dump = meta_gstripe_dump + .alloc_struct = meta_gstripe_alloc_struct, + .init_vol2meta = meta_gstripe_init_vol2meta, + .init_meta2vol = meta_gstripe_init_meta2vol, + .encode = meta_gstripe_encode, + .decode = meta_gstripe_decode, + .get_block = meta_gstripe_get_block, + .write_block = meta_gstripe_write_block, + .has_valid_magic = meta_gstripe_has_valid_magic, + .compare_uuids = meta_gstripe_compare_uuids, + .inc_counter = meta_gstripe_inc_counter, + .save = meta_gstripe_save, + .get_devname = meta_gstripe_get_devname, + .get_level = meta_gstripe_get_level, + .get_data_offset = meta_gstripe_get_data_offset, + .get_size = meta_gstripe_get_size, + .get_flags = meta_gstripe_get_flags, + .get_type = meta_gstripe_get_type, + .dump = meta_gstripe_dump }; static void *meta_gstripe_alloc_struct(void) diff --git a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c index 4fbb0ac9d7..c41a1cf1ff 100644 --- a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c +++ b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c @@ -52,47 +52,44 @@ #include "softraidvar.h" -static void *meta_softraid_alloc_struct(void); -static errno_t meta_softraid_init_vol2meta(const hr_volume_t *, - void *); -static errno_t meta_softraid_init_meta2vol(const list_t *, - hr_volume_t *); -static void meta_softraid_encode(void *, void *); -static errno_t meta_softraid_decode(const void *, void *); -static errno_t meta_softraid_get_block(service_id_t, void **); -static errno_t meta_softraid_write_block(service_id_t, const void *); -static bool meta_softraid_has_valid_magic(const void *); -static bool meta_softraid_compare_uuids(const void *, - const void *); -static void meta_softraid_inc_counter(void *); -static errno_t meta_softraid_save(hr_volume_t *, bool); -static const char *meta_softraid_get_devname(const void *); -static hr_level_t meta_softraid_get_level(const void *); -static uint64_t meta_softraid_get_data_offset(void); -static size_t meta_softraid_get_size(void); -static uint8_t meta_softraid_get_flags(void); +static void *meta_softraid_alloc_struct(void); +static errno_t meta_softraid_init_vol2meta(const hr_volume_t *, void *); +static errno_t meta_softraid_init_meta2vol(const list_t *, hr_volume_t *); +static void meta_softraid_encode(void *, void *); +static errno_t meta_softraid_decode(const void *, void *); +static errno_t meta_softraid_get_block(service_id_t, void **); +static errno_t meta_softraid_write_block(service_id_t, const void *); +static bool meta_softraid_has_valid_magic(const void *); +static bool meta_softraid_compare_uuids(const void *, const void *); +static void meta_softraid_inc_counter(void *); +static errno_t meta_softraid_save(hr_volume_t *, bool); +static const char *meta_softraid_get_devname(const void *); +static hr_level_t meta_softraid_get_level(const void *); +static uint64_t meta_softraid_get_data_offset(void); +static size_t meta_softraid_get_size(void); +static uint8_t meta_softraid_get_flags(void); static hr_metadata_type_t meta_softraid_get_type(void); -static void meta_softraid_dump(const void *); +static void meta_softraid_dump(const void *); hr_superblock_ops_t metadata_softraid_ops = { - .alloc_struct = meta_softraid_alloc_struct, - .init_vol2meta = meta_softraid_init_vol2meta, - .init_meta2vol = meta_softraid_init_meta2vol, - .encode = meta_softraid_encode, - .decode = meta_softraid_decode, - .get_block = meta_softraid_get_block, - .write_block = meta_softraid_write_block, - .has_valid_magic = meta_softraid_has_valid_magic, - .compare_uuids = meta_softraid_compare_uuids, - .inc_counter = meta_softraid_inc_counter, - .save = meta_softraid_save, - .get_devname = meta_softraid_get_devname, - .get_level = meta_softraid_get_level, - .get_data_offset = meta_softraid_get_data_offset, - .get_size = meta_softraid_get_size, - .get_flags = meta_softraid_get_flags, - .get_type = meta_softraid_get_type, - .dump = meta_softraid_dump + .alloc_struct = meta_softraid_alloc_struct, + .init_vol2meta = meta_softraid_init_vol2meta, + .init_meta2vol = meta_softraid_init_meta2vol, + .encode = meta_softraid_encode, + .decode = meta_softraid_decode, + .get_block = meta_softraid_get_block, + .write_block = meta_softraid_write_block, + .has_valid_magic = meta_softraid_has_valid_magic, + .compare_uuids = meta_softraid_compare_uuids, + .inc_counter = meta_softraid_inc_counter, + .save = meta_softraid_save, + .get_devname = meta_softraid_get_devname, + .get_level = meta_softraid_get_level, + .get_data_offset = meta_softraid_get_data_offset, + .get_size = meta_softraid_get_size, + .get_flags = meta_softraid_get_flags, + .get_type = meta_softraid_get_type, + .dump = meta_softraid_dump }; static void *meta_softraid_alloc_struct(void) diff --git a/uspace/srv/bd/hr/metadata/native.c b/uspace/srv/bd/hr/metadata/native.c index 569cd52af0..b2b93957a4 100644 --- a/uspace/srv/bd/hr/metadata/native.c +++ b/uspace/srv/bd/hr/metadata/native.c @@ -52,45 +52,44 @@ #include "native.h" -static void *meta_native_alloc_struct(void); -static errno_t meta_native_init_vol2meta(const hr_volume_t *, void *); -static errno_t meta_native_init_meta2vol(const list_t *, - hr_volume_t *); -static void meta_native_encode(void *, void *); -static errno_t meta_native_decode(const void *, void *); -static errno_t meta_native_get_block(service_id_t, void **); -static errno_t meta_native_write_block(service_id_t, const void *); -static bool meta_native_has_valid_magic(const void *); -static bool meta_native_compare_uuids(const void *, const void *); -static void meta_native_inc_counter(void *); -static errno_t meta_native_save(hr_volume_t *, bool); -static const char *meta_native_get_devname(const void *); -static hr_level_t meta_native_get_level(const void *); -static uint64_t meta_native_get_data_offset(void); -static size_t meta_native_get_size(void); -static uint8_t meta_native_get_flags(void); +static void *meta_native_alloc_struct(void); +static errno_t meta_native_init_vol2meta(const hr_volume_t *, void *); +static errno_t meta_native_init_meta2vol(const list_t *, hr_volume_t *); +static void meta_native_encode(void *, void *); +static errno_t meta_native_decode(const void *, void *); +static errno_t meta_native_get_block(service_id_t, void **); +static errno_t meta_native_write_block(service_id_t, const void *); +static bool meta_native_has_valid_magic(const void *); +static bool meta_native_compare_uuids(const void *, const void *); +static void meta_native_inc_counter(void *); +static errno_t meta_native_save(hr_volume_t *, bool); +static const char *meta_native_get_devname(const void *); +static hr_level_t meta_native_get_level(const void *); +static uint64_t meta_native_get_data_offset(void); +static size_t meta_native_get_size(void); +static uint8_t meta_native_get_flags(void); static hr_metadata_type_t meta_native_get_type(void); -static void meta_native_dump(const void *); +static void meta_native_dump(const void *); hr_superblock_ops_t metadata_native_ops = { - .alloc_struct = meta_native_alloc_struct, - .init_vol2meta = meta_native_init_vol2meta, - .init_meta2vol = meta_native_init_meta2vol, - .encode = meta_native_encode, - .decode = meta_native_decode, - .get_block = meta_native_get_block, - .write_block = meta_native_write_block, - .has_valid_magic = meta_native_has_valid_magic, - .compare_uuids = meta_native_compare_uuids, - .inc_counter = meta_native_inc_counter, - .save = meta_native_save, - .get_devname = meta_native_get_devname, - .get_level = meta_native_get_level, - .get_data_offset = meta_native_get_data_offset, - .get_size = meta_native_get_size, - .get_flags = meta_native_get_flags, - .get_type = meta_native_get_type, - .dump = meta_native_dump + .alloc_struct = meta_native_alloc_struct, + .init_vol2meta = meta_native_init_vol2meta, + .init_meta2vol = meta_native_init_meta2vol, + .encode = meta_native_encode, + .decode = meta_native_decode, + .get_block = meta_native_get_block, + .write_block = meta_native_write_block, + .has_valid_magic = meta_native_has_valid_magic, + .compare_uuids = meta_native_compare_uuids, + .inc_counter = meta_native_inc_counter, + .save = meta_native_save, + .get_devname = meta_native_get_devname, + .get_level = meta_native_get_level, + .get_data_offset = meta_native_get_data_offset, + .get_size = meta_native_get_size, + .get_flags = meta_native_get_flags, + .get_type = meta_native_get_type, + .dump = meta_native_dump }; static void *meta_native_alloc_struct(void) diff --git a/uspace/srv/bd/hr/metadata/native.h b/uspace/srv/bd/hr/metadata/native.h index 44c77dcfa8..7519d3e734 100644 --- a/uspace/srv/bd/hr/metadata/native.h +++ b/uspace/srv/bd/hr/metadata/native.h @@ -41,36 +41,36 @@ /* * Metadata is stored on the last block of an extent. */ -#define HR_NATIVE_META_SIZE 1 /* in blocks */ -#define HR_NATIVE_DATA_OFF 0 +#define HR_NATIVE_META_SIZE 1 /* in blocks */ +#define HR_NATIVE_DATA_OFF 0 -#define HR_NATIVE_MAGIC_STR "HelenRAID" -#define HR_NATIVE_MAGIC_SIZE 16 -#define HR_NATIVE_UUID_LEN 16 -#define HR_NATIVE_METADATA_VERSION 1 +#define HR_NATIVE_MAGIC_STR "HelenRAID" +#define HR_NATIVE_MAGIC_SIZE 16 +#define HR_NATIVE_UUID_LEN 16 +#define HR_NATIVE_METADATA_VERSION 1 struct hr_metadata { - char magic[HR_NATIVE_MAGIC_SIZE]; + char magic[HR_NATIVE_MAGIC_SIZE]; - uint8_t uuid[HR_NATIVE_UUID_LEN]; + uint8_t uuid[HR_NATIVE_UUID_LEN]; - uint64_t data_blkno; /* usable blocks */ - uint64_t truncated_blkno; /* size of smallest extent */ + uint64_t data_blkno; /* usable blocks */ + uint64_t truncated_blkno; /* size of smallest extent */ - uint64_t data_offset; - uint64_t counter; + uint64_t data_offset; + uint64_t counter; - uint32_t version; /* XXX: yet unused */ - uint32_t extent_no; - uint32_t index; /* index of extent in volume */ - uint32_t level; + uint32_t version; /* XXX: yet unused */ + uint32_t extent_no; + uint32_t index; /* index of extent in volume */ + uint32_t level; - uint32_t layout; - uint32_t strip_size; + uint32_t layout; + uint32_t strip_size; - uint32_t bsize; + uint32_t bsize; - char devname[HR_DEVNAME_LEN]; + char devname[HR_DEVNAME_LEN]; } __attribute__((packed)); #endif diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index 3b1ad00bd9..0d8f91c307 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -52,30 +52,30 @@ #include "util.h" #include "var.h" -static void hr_raid0_update_vol_state(hr_volume_t *); -static void hr_raid0_state_callback(hr_volume_t *, size_t, errno_t); -static errno_t hr_raid0_bd_op(hr_bd_op_type_t, bd_srv_t *, aoff64_t, size_t, +static void hr_raid0_update_vol_state(hr_volume_t *); +static void hr_raid0_state_callback(hr_volume_t *, size_t, errno_t); +static errno_t hr_raid0_bd_op(hr_bd_op_type_t, bd_srv_t *, aoff64_t, size_t, void *, const void *, size_t); /* bdops */ -static errno_t hr_raid0_bd_open(bd_srvs_t *, bd_srv_t *); -static errno_t hr_raid0_bd_close(bd_srv_t *); -static errno_t hr_raid0_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, +static errno_t hr_raid0_bd_open(bd_srvs_t *, bd_srv_t *); +static errno_t hr_raid0_bd_close(bd_srv_t *); +static errno_t hr_raid0_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, size_t); -static errno_t hr_raid0_bd_sync_cache(bd_srv_t *, aoff64_t, size_t); -static errno_t hr_raid0_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, +static errno_t hr_raid0_bd_sync_cache(bd_srv_t *, aoff64_t, size_t); +static errno_t hr_raid0_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, const void *, size_t); -static errno_t hr_raid0_bd_get_block_size(bd_srv_t *, size_t *); -static errno_t hr_raid0_bd_get_num_blocks(bd_srv_t *, aoff64_t *); +static errno_t hr_raid0_bd_get_block_size(bd_srv_t *, size_t *); +static errno_t hr_raid0_bd_get_num_blocks(bd_srv_t *, aoff64_t *); static bd_ops_t hr_raid0_bd_ops = { - .open = hr_raid0_bd_open, - .close = hr_raid0_bd_close, - .sync_cache = hr_raid0_bd_sync_cache, - .read_blocks = hr_raid0_bd_read_blocks, - .write_blocks = hr_raid0_bd_write_blocks, - .get_block_size = hr_raid0_bd_get_block_size, - .get_num_blocks = hr_raid0_bd_get_num_blocks + .open = hr_raid0_bd_open, + .close = hr_raid0_bd_close, + .sync_cache = hr_raid0_bd_sync_cache, + .read_blocks = hr_raid0_bd_read_blocks, + .write_blocks = hr_raid0_bd_write_blocks, + .get_block_size = hr_raid0_bd_get_block_size, + .get_num_blocks = hr_raid0_bd_get_num_blocks }; extern loc_srv_t *hr_srv; diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index d76eeed003..f1d8c3be97 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -55,37 +55,37 @@ #include "util.h" #include "var.h" -static void hr_raid1_update_vol_state(hr_volume_t *); -static void hr_raid1_ext_state_callback(hr_volume_t *, size_t, errno_t); -static size_t hr_raid1_count_good_extents(hr_volume_t *, uint64_t, size_t, +static void hr_raid1_update_vol_state(hr_volume_t *); +static void hr_raid1_ext_state_callback(hr_volume_t *, size_t, errno_t); +static size_t hr_raid1_count_good_extents(hr_volume_t *, uint64_t, size_t, uint64_t); -static errno_t hr_raid1_bd_op(hr_bd_op_type_t, bd_srv_t *, aoff64_t, size_t, +static errno_t hr_raid1_bd_op(hr_bd_op_type_t, bd_srv_t *, aoff64_t, size_t, void *, const void *, size_t); -static errno_t hr_raid1_rebuild(void *); -static errno_t init_rebuild(hr_volume_t *, size_t *); -static errno_t swap_hs(hr_volume_t *, size_t, size_t); -static errno_t hr_raid1_restore_blocks(hr_volume_t *, size_t, uint64_t, size_t, +static errno_t hr_raid1_rebuild(void *); +static errno_t init_rebuild(hr_volume_t *, size_t *); +static errno_t swap_hs(hr_volume_t *, size_t, size_t); +static errno_t hr_raid1_restore_blocks(hr_volume_t *, size_t, uint64_t, size_t, void *); /* bdops */ -static errno_t hr_raid1_bd_open(bd_srvs_t *, bd_srv_t *); -static errno_t hr_raid1_bd_close(bd_srv_t *); -static errno_t hr_raid1_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, +static errno_t hr_raid1_bd_open(bd_srvs_t *, bd_srv_t *); +static errno_t hr_raid1_bd_close(bd_srv_t *); +static errno_t hr_raid1_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, size_t); -static errno_t hr_raid1_bd_sync_cache(bd_srv_t *, aoff64_t, size_t); -static errno_t hr_raid1_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, +static errno_t hr_raid1_bd_sync_cache(bd_srv_t *, aoff64_t, size_t); +static errno_t hr_raid1_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, const void *, size_t); -static errno_t hr_raid1_bd_get_block_size(bd_srv_t *, size_t *); -static errno_t hr_raid1_bd_get_num_blocks(bd_srv_t *, aoff64_t *); +static errno_t hr_raid1_bd_get_block_size(bd_srv_t *, size_t *); +static errno_t hr_raid1_bd_get_num_blocks(bd_srv_t *, aoff64_t *); static bd_ops_t hr_raid1_bd_ops = { - .open = hr_raid1_bd_open, - .close = hr_raid1_bd_close, - .sync_cache = hr_raid1_bd_sync_cache, - .read_blocks = hr_raid1_bd_read_blocks, - .write_blocks = hr_raid1_bd_write_blocks, - .get_block_size = hr_raid1_bd_get_block_size, - .get_num_blocks = hr_raid1_bd_get_num_blocks + .open = hr_raid1_bd_open, + .close = hr_raid1_bd_close, + .sync_cache = hr_raid1_bd_sync_cache, + .read_blocks = hr_raid1_bd_read_blocks, + .write_blocks = hr_raid1_bd_write_blocks, + .get_block_size = hr_raid1_bd_get_block_size, + .get_num_blocks = hr_raid1_bd_get_num_blocks }; extern loc_srv_t *hr_srv; diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index f179636d7a..3e6ed3e52e 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -53,40 +53,41 @@ #include "util.h" #include "var.h" -static errno_t hr_raid5_vol_usable(hr_volume_t *); -static ssize_t hr_raid5_get_bad_ext(hr_volume_t *); -static errno_t hr_raid5_update_vol_state(hr_volume_t *); -static void hr_raid5_handle_extent_error(hr_volume_t *, size_t, errno_t); -static void xor(void *, const void *, size_t); -static errno_t hr_raid5_read_degraded(hr_volume_t *, uint64_t, uint64_t, +static errno_t hr_raid5_vol_usable(hr_volume_t *); +static ssize_t hr_raid5_get_bad_ext(hr_volume_t *); +static errno_t hr_raid5_update_vol_state(hr_volume_t *); +static void hr_raid5_handle_extent_error(hr_volume_t *, size_t, errno_t); +static void xor(void *, const void *, size_t); + +static errno_t hr_raid5_read_degraded(hr_volume_t *, uint64_t, uint64_t, void *, size_t); -static errno_t hr_raid5_write(hr_volume_t *, uint64_t, uint64_t, aoff64_t, +static errno_t hr_raid5_write(hr_volume_t *, uint64_t, uint64_t, aoff64_t, const void *, size_t); -static errno_t hr_raid5_write_parity(hr_volume_t *, uint64_t, uint64_t, +static errno_t hr_raid5_write_parity(hr_volume_t *, uint64_t, uint64_t, uint64_t, const void *, size_t); -static errno_t hr_raid5_bd_op(hr_bd_op_type_t, bd_srv_t *, aoff64_t, size_t, +static errno_t hr_raid5_bd_op(hr_bd_op_type_t, bd_srv_t *, aoff64_t, size_t, void *, const void *, size_t); -static errno_t hr_raid5_rebuild(void *); +static errno_t hr_raid5_rebuild(void *); /* bdops */ -static errno_t hr_raid5_bd_open(bd_srvs_t *, bd_srv_t *); -static errno_t hr_raid5_bd_close(bd_srv_t *); -static errno_t hr_raid5_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, +static errno_t hr_raid5_bd_open(bd_srvs_t *, bd_srv_t *); +static errno_t hr_raid5_bd_close(bd_srv_t *); +static errno_t hr_raid5_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, size_t); -static errno_t hr_raid5_bd_sync_cache(bd_srv_t *, aoff64_t, size_t); -static errno_t hr_raid5_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, +static errno_t hr_raid5_bd_sync_cache(bd_srv_t *, aoff64_t, size_t); +static errno_t hr_raid5_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, const void *, size_t); -static errno_t hr_raid5_bd_get_block_size(bd_srv_t *, size_t *); -static errno_t hr_raid5_bd_get_num_blocks(bd_srv_t *, aoff64_t *); +static errno_t hr_raid5_bd_get_block_size(bd_srv_t *, size_t *); +static errno_t hr_raid5_bd_get_num_blocks(bd_srv_t *, aoff64_t *); static bd_ops_t hr_raid5_bd_ops = { - .open = hr_raid5_bd_open, - .close = hr_raid5_bd_close, - .sync_cache = hr_raid5_bd_sync_cache, - .read_blocks = hr_raid5_bd_read_blocks, - .write_blocks = hr_raid5_bd_write_blocks, - .get_block_size = hr_raid5_bd_get_block_size, - .get_num_blocks = hr_raid5_bd_get_num_blocks + .open = hr_raid5_bd_open, + .close = hr_raid5_bd_close, + .sync_cache = hr_raid5_bd_sync_cache, + .read_blocks = hr_raid5_bd_read_blocks, + .write_blocks = hr_raid5_bd_write_blocks, + .get_block_size = hr_raid5_bd_get_block_size, + .get_num_blocks = hr_raid5_bd_get_num_blocks }; extern loc_srv_t *hr_srv; diff --git a/uspace/srv/bd/hr/superblock.h b/uspace/srv/bd/hr/superblock.h index c866679b83..e006806926 100644 --- a/uspace/srv/bd/hr/superblock.h +++ b/uspace/srv/bd/hr/superblock.h @@ -43,28 +43,28 @@ typedef struct hr_volume hr_volume_t; #define HR_METADATA_HOTSPARE_SUPPORT 0x01 typedef struct hr_superblock_ops { - void *(*alloc_struct)(void); - errno_t (*init_vol2meta)(const hr_volume_t *, void *); - errno_t (*init_meta2vol)(const list_t *, hr_volume_t *); - void (*encode)(void *, void *); - errno_t (*decode)(const void *, void *); - errno_t (*get_block)(service_id_t, void **); - errno_t (*write_block)(service_id_t, const void *); - bool (*has_valid_magic)(const void *); - bool (*compare_uuids)(const void *, const void *); - void (*inc_counter)(void *); - errno_t (*save)(hr_volume_t *, bool); - const char *(*get_devname)(const void *); - hr_level_t (*get_level)(const void *); - uint64_t (*get_data_offset)(void); - size_t (*get_size)(void); - uint8_t (*get_flags)(void); - void (*dump)(const void *); + void *(*alloc_struct)(void); + errno_t (*init_vol2meta)(const hr_volume_t *, void *); + errno_t (*init_meta2vol)(const list_t *, hr_volume_t *); + void (*encode)(void *, void *); + errno_t (*decode)(const void *, void *); + errno_t (*get_block)(service_id_t, void **); + errno_t (*write_block)(service_id_t, const void *); + bool (*has_valid_magic)(const void *); + bool (*compare_uuids)(const void *, const void *); + void (*inc_counter)(void *); + errno_t (*save)(hr_volume_t *, bool); + const char *(*get_devname)(const void *); + hr_level_t (*get_level)(const void *); + uint64_t (*get_data_offset)(void); + size_t (*get_size)(void); + uint8_t (*get_flags)(void); + void (*dump)(const void *); hr_metadata_type_t (*get_type)(void); } hr_superblock_ops_t; extern hr_superblock_ops_t *get_type_ops(hr_metadata_type_t); -extern errno_t find_metadata(service_id_t, void **, hr_metadata_type_t *); +extern errno_t find_metadata(service_id_t, void **, hr_metadata_type_t *); #endif diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 08a526bf58..b61f7a235b 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -54,18 +54,18 @@ #include "util.h" #include "var.h" -static bool hr_range_lock_overlap(hr_range_lock_t *, hr_range_lock_t *); -static errno_t hr_add_svc_linked_to_list(list_t *, service_id_t, bool, - void *); -static void free_dev_list_member(struct dev_list_member *); -static void free_svc_id_list(list_t *); -static errno_t hr_fill_disk_part_svcs_list(list_t *); -static errno_t block_init_dev_list(list_t *); -static void block_fini_dev_list(list_t *); -static errno_t hr_util_get_matching_md_svcs_list(list_t *, list_t *, +static bool hr_range_lock_overlap(hr_range_lock_t *, hr_range_lock_t *); +static errno_t hr_add_svc_linked_to_list(list_t *, service_id_t, bool, void *); +static void free_dev_list_member(struct dev_list_member *); +static void free_svc_id_list(list_t *); +static errno_t hr_fill_disk_part_svcs_list(list_t *); +static errno_t block_init_dev_list(list_t *); +static void block_fini_dev_list(list_t *); +static errno_t hr_util_get_matching_md_svcs_list(list_t *, list_t *, service_id_t, hr_metadata_type_t, void *); -static errno_t hr_util_assemble_from_matching_list(list_t *, hr_metadata_type_t); -static errno_t hr_fill_svcs_list_from_cfg(hr_config_t *, list_t *); +static errno_t hr_util_assemble_from_matching_list(list_t *, + hr_metadata_type_t); +static errno_t hr_fill_svcs_list_from_cfg(hr_config_t *, list_t *); #define HR_RL_LIST_LOCK(vol) (fibril_mutex_lock(&(vol)->range_lock_list_lock)) #define HR_RL_LIST_UNLOCK(vol) \ diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index 8746af345d..668f5759df 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -45,12 +45,12 @@ #include "var.h" struct dev_list_member { - link_t link; - service_id_t svc_id; - void *md; - bool inited; - bool md_present; - bool fini; + link_t link; + service_id_t svc_id; + void *md; + bool inited; + bool md_present; + bool fini; }; #define HR_DEBUG(format, ...) \ @@ -65,35 +65,30 @@ struct dev_list_member { #define HR_ERROR(format, ...) \ log_msg(LOG_DEFAULT, LVL_ERROR, format, ##__VA_ARGS__) - -extern errno_t hr_create_vol_struct(hr_volume_t **, hr_level_t, - const char *, hr_metadata_type_t); -extern void hr_destroy_vol_struct(hr_volume_t *); -extern errno_t hr_get_volume_svcs(size_t *, service_id_t **); -extern hr_volume_t *hr_get_volume(service_id_t); -extern errno_t hr_remove_volume(service_id_t); -extern errno_t hr_init_extents_from_cfg(hr_volume_t *, hr_config_t *); -extern void hr_fini_devs(hr_volume_t *); -extern errno_t hr_register_volume(hr_volume_t *); -extern errno_t hr_check_ba_range(hr_volume_t *, size_t, uint64_t); -extern void hr_add_ba_offset(hr_volume_t *, uint64_t *); -extern void hr_update_ext_state(hr_volume_t *, size_t, - hr_ext_state_t); -extern void hr_update_hotspare_state(hr_volume_t *, size_t, - hr_ext_state_t); -extern void hr_update_vol_state(hr_volume_t *, hr_vol_state_t); -extern void hr_update_ext_svc_id(hr_volume_t *, size_t, - service_id_t); -extern void hr_update_hotspare_svc_id(hr_volume_t *, size_t, - service_id_t); -extern void hr_sync_all_extents(hr_volume_t *); -extern size_t hr_count_extents(hr_volume_t *, hr_ext_state_t); -extern void hr_mark_vol_state_dirty(hr_volume_t *); -extern void hr_range_lock_release(hr_range_lock_t *); -extern hr_range_lock_t *hr_range_lock_acquire(hr_volume_t *, uint64_t, +extern errno_t hr_create_vol_struct(hr_volume_t **, hr_level_t, const char *, + hr_metadata_type_t); +extern void hr_destroy_vol_struct(hr_volume_t *); +extern errno_t hr_get_volume_svcs(size_t *, service_id_t **); +extern hr_volume_t *hr_get_volume(service_id_t); +extern errno_t hr_remove_volume(service_id_t); +extern errno_t hr_init_extents_from_cfg(hr_volume_t *, hr_config_t *); +extern void hr_fini_devs(hr_volume_t *); +extern errno_t hr_register_volume(hr_volume_t *); +extern errno_t hr_check_ba_range(hr_volume_t *, size_t, uint64_t); +extern void hr_add_ba_offset(hr_volume_t *, uint64_t *); +extern void hr_update_ext_state(hr_volume_t *, size_t, hr_ext_state_t); +extern void hr_update_hotspare_state(hr_volume_t *, size_t, hr_ext_state_t); +extern void hr_update_vol_state(hr_volume_t *, hr_vol_state_t); +extern void hr_update_ext_svc_id(hr_volume_t *, size_t, service_id_t); +extern void hr_update_hotspare_svc_id(hr_volume_t *, size_t, service_id_t); +extern void hr_sync_all_extents(hr_volume_t *); +extern size_t hr_count_extents(hr_volume_t *, hr_ext_state_t); +extern void hr_mark_vol_state_dirty(hr_volume_t *); +extern void hr_range_lock_release(hr_range_lock_t *); +extern hr_range_lock_t *hr_range_lock_acquire(hr_volume_t *, uint64_t, uint64_t); -extern errno_t hr_util_try_assemble(hr_config_t *, size_t *); -extern errno_t hr_util_add_hotspare(hr_volume_t *, service_id_t); +extern errno_t hr_util_try_assemble(hr_config_t *, size_t *); +extern errno_t hr_util_add_hotspare(hr_volume_t *, service_id_t); #endif diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index f5599f8e62..04519a2613 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -46,8 +46,8 @@ #include "fge.h" #include "superblock.h" -#define NAME "hr" -#define HR_STRIP_SIZE DATA_XFER_LIMIT +#define NAME "hr" +#define HR_STRIP_SIZE DATA_XFER_LIMIT struct hr_volume; typedef struct hr_volume hr_volume_t; @@ -55,55 +55,55 @@ typedef struct hr_metadata hr_metadata_t; typedef struct hr_superblock_ops hr_superblock_ops_t; typedef struct hr_ops { - errno_t (*create)(hr_volume_t *); - errno_t (*init)(hr_volume_t *); - void (*state_event)(hr_volume_t *); - errno_t (*add_hotspare)(hr_volume_t *, service_id_t); + errno_t (*create)(hr_volume_t *); + errno_t (*init)(hr_volume_t *); + void (*state_event)(hr_volume_t *); + errno_t (*add_hotspare)(hr_volume_t *, service_id_t); } hr_ops_t; typedef struct hr_volume { - link_t lvolumes; /* link to all volumes list */ - hr_ops_t hr_ops; /* level init and create fcns */ - bd_srvs_t hr_bds; /* block interface to the vol */ - service_id_t svc_id; /* service id */ + link_t lvolumes; /* link to all volumes list */ + hr_ops_t hr_ops; /* level init and create fcns */ + bd_srvs_t hr_bds; /* block interface to the vol */ + service_id_t svc_id; /* service id */ - fibril_mutex_t lock; /* XXX: gone after para */ - list_t range_lock_list; /* list of range locks */ - fibril_mutex_t range_lock_list_lock; /* range locks list lock */ - hr_fpool_t *fge; /* fibril pool */ + fibril_mutex_t lock; /* XXX: gone after para */ + list_t range_lock_list; /* list of range locks */ + fibril_mutex_t range_lock_list_lock; /* range locks list lock */ + hr_fpool_t *fge; /* fibril pool */ - void *in_mem_md; - fibril_mutex_t md_lock; /* lock protecting in_mem_md */ + void *in_mem_md; + fibril_mutex_t md_lock; /* lock protecting in_mem_md */ hr_superblock_ops_t *meta_ops; /* invariants */ - size_t extent_no; /* number of extents */ - size_t bsize; /* block size */ - uint64_t truncated_blkno; /* blkno per extent */ - uint64_t data_blkno; /* no. of user usable blocks */ - uint64_t data_offset; /* user data offset in blocks */ - uint32_t strip_size; /* strip size */ - hr_level_t level; /* volume level */ - hr_layout_t layout; /* RAID Level Qualifier */ - char devname[HR_DEVNAME_LEN]; + size_t extent_no; /* number of extents */ + size_t bsize; /* block size */ + uint64_t truncated_blkno; /* blkno per extent */ + uint64_t data_blkno; /* no. of user usable blocks */ + uint64_t data_offset; /* user data offset in blocks */ + uint32_t strip_size; /* strip size */ + hr_level_t level; /* volume level */ + hr_layout_t layout; /* RAID Level Qualifier */ + char devname[HR_DEVNAME_LEN]; - hr_extent_t extents[HR_MAX_EXTENTS]; - fibril_rwlock_t extents_lock; /* extent service id lock */ + hr_extent_t extents[HR_MAX_EXTENTS]; + fibril_rwlock_t extents_lock; /* extent service id lock */ - size_t hotspare_no; /* no. of available hotspares */ - hr_extent_t hotspares[HR_MAX_HOTSPARES]; - fibril_mutex_t hotspare_lock; /* lock protecting hotspares */ + size_t hotspare_no; /* no. of available hotspares */ + hr_extent_t hotspares[HR_MAX_HOTSPARES]; + fibril_mutex_t hotspare_lock; /* lock protecting hotspares */ - fibril_rwlock_t states_lock; /* states lock */ + fibril_rwlock_t states_lock; /* states lock */ - _Atomic bool state_dirty; /* dirty state */ + _Atomic bool state_dirty; /* dirty state */ /* XXX: atomic_uint_least64_t? */ - _Atomic uint64_t rebuild_blk; /* rebuild position */ - _Atomic int open_cnt; /* open/close() counter */ - hr_vol_state_t state; /* volume state */ - void (*state_callback)(hr_volume_t *, size_t, errno_t); + _Atomic uint64_t rebuild_blk; /* rebuild position */ + _Atomic int open_cnt; /* open/close() counter */ + hr_vol_state_t state; /* volume state */ + void (*state_callback)(hr_volume_t *, size_t, errno_t); } hr_volume_t; typedef enum { @@ -117,30 +117,30 @@ typedef enum { #define NO_STATE_CALLBACK false typedef struct hr_range_lock { - link_t link; - fibril_mutex_t lock; - hr_volume_t *vol; /* back-pointer to volume */ - uint64_t off; /* start of the range */ - uint64_t len; /* length of the range */ - - size_t pending; /* prot. by vol->range_lock_list_lock */ - bool ignore; /* prot. by vol->range_lock_list_lock */ + link_t link; + fibril_mutex_t lock; + hr_volume_t *vol; /* back-pointer to volume */ + uint64_t off; /* start of the range */ + uint64_t len; /* length of the range */ + + size_t pending; /* prot. by vol->range_lock_list_lock */ + bool ignore; /* prot. by vol->range_lock_list_lock */ } hr_range_lock_t; -extern errno_t hr_raid0_create(hr_volume_t *); -extern errno_t hr_raid1_create(hr_volume_t *); -extern errno_t hr_raid5_create(hr_volume_t *); +extern errno_t hr_raid0_create(hr_volume_t *); +extern errno_t hr_raid1_create(hr_volume_t *); +extern errno_t hr_raid5_create(hr_volume_t *); -extern errno_t hr_raid0_init(hr_volume_t *); -extern errno_t hr_raid1_init(hr_volume_t *); -extern errno_t hr_raid5_init(hr_volume_t *); +extern errno_t hr_raid0_init(hr_volume_t *); +extern errno_t hr_raid1_init(hr_volume_t *); +extern errno_t hr_raid5_init(hr_volume_t *); -extern void hr_raid0_state_event(hr_volume_t *); -extern void hr_raid1_state_event(hr_volume_t *); -extern void hr_raid5_state_event(hr_volume_t *); +extern void hr_raid0_state_event(hr_volume_t *); +extern void hr_raid1_state_event(hr_volume_t *); +extern void hr_raid5_state_event(hr_volume_t *); -extern errno_t hr_raid1_add_hotspare(hr_volume_t *, service_id_t); -extern errno_t hr_raid5_add_hotspare(hr_volume_t *, service_id_t); +extern errno_t hr_raid1_add_hotspare(hr_volume_t *, service_id_t); +extern errno_t hr_raid5_add_hotspare(hr_volume_t *, service_id_t); #endif From c5b60e2529dc37633386931bf11917269fcd5175 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 20 May 2025 20:38:22 +0200 Subject: [PATCH 232/324] hr: use PRIun to print service_id_t --- uspace/srv/bd/hr/hr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 3da9446c35..2d4e5d4b63 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -166,7 +166,8 @@ static void hr_create_srv(ipc_call_t *icall) list_append(&vol->lvolumes, &hr_volumes); fibril_rwlock_write_unlock(&hr_volumes_lock); - HR_NOTE("created volume \"%s\" (%lu)\n", vol->devname, vol->svc_id); + HR_NOTE("created volume \"%s\" (%" PRIun ")\n", vol->devname, + vol->svc_id); free(cfg); async_answer_0(icall, rc); From 49da04407e5900013a273fd9ee22ded0a7af5acb Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 20 May 2025 21:24:46 +0200 Subject: [PATCH 233/324] hr: fge: move types to fge.h --- uspace/srv/bd/hr/fge.c | 52 ----------------------------------------- uspace/srv/bd/hr/fge.h | 53 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 51 insertions(+), 54 deletions(-) diff --git a/uspace/srv/bd/hr/fge.c b/uspace/srv/bd/hr/fge.c index 1eafc67c98..4f02a5d0d7 100644 --- a/uspace/srv/bd/hr/fge.c +++ b/uspace/srv/bd/hr/fge.c @@ -52,12 +52,6 @@ #include "fge.h" -/* forward declarations */ -struct fge_fibril_data; -typedef struct fge_fibril_data fge_fibril_data_t; -struct wu_queue; -typedef struct wu_queue wu_queue_t; - static void *hr_fpool_make_storage(hr_fpool_t *, ssize_t *); static void hr_fpool_group_epilogue(hr_fpool_t *); static errno_t fge_fibril(void *); @@ -66,52 +60,6 @@ static void wu_queue_push(wu_queue_t *, fge_fibril_data_t *); static void wu_queue_pop(wu_queue_t *, fge_fibril_data_t *); static ssize_t hr_fpool_get_free_slot(hr_fpool_t *); -struct fge_fibril_data { - hr_wu_t wu; /* work unit function pointer */ - void *arg; /* work unit function argument */ - hr_fgroup_t *group; /* back-pointer to group */ - ssize_t memslot; /* index to pool bitmap slot */ -}; - -struct wu_queue { - fibril_mutex_t lock; - fibril_condvar_t not_empty; - fibril_condvar_t not_full; - fge_fibril_data_t *fexecs; /* circ-buf memory */ - circ_buf_t cbuf; -}; - -struct hr_fpool { - fibril_mutex_t lock; - bitmap_t bitmap; /* memory slot bitmap */ - wu_queue_t queue; - fid_t *fibrils; - uint8_t *wu_storage; /* pre-allocated pool storage */ - size_t fibril_cnt; - size_t max_wus; - size_t active_groups; - bool stop; - size_t wu_size; - size_t wu_storage_free_count; - fibril_condvar_t all_wus_done; -}; - -struct hr_fgroup { - hr_fpool_t *pool;/* back-pointer to pool */ - size_t wu_cnt;/* upper bound of work units */ - size_t submitted; /* number of submitted jobs */ - size_t reserved_cnt; /* no. of reserved wu storage slots */ - size_t reserved_avail; - size_t *memslots; /* indices to pool bitmap */ - void *own_mem; /* own allocated memory */ - size_t own_used; /* own memory slots used counter */ - errno_t final_errno; /* agreggated errno */ - size_t finished_okay; /* no. of wus that ended with EOK */ - size_t finished_fail; /* no. of wus that ended with != EOK */ - fibril_mutex_t lock; - fibril_condvar_t all_done; -}; - hr_fpool_t *hr_fpool_create(size_t fibril_cnt, size_t max_wus, size_t wu_storage_size) { diff --git a/uspace/srv/bd/hr/fge.h b/uspace/srv/bd/hr/fge.h index fb433e3a78..089f9d8da7 100644 --- a/uspace/srv/bd/hr/fge.h +++ b/uspace/srv/bd/hr/fge.h @@ -37,16 +37,65 @@ #ifndef _HR_FGE_H #define _HR_FGE_H +#include +#include #include #include -struct hr_fpool; +/* forward declarations */ typedef struct hr_fpool hr_fpool_t; -struct hr_fgroup; typedef struct hr_fgroup hr_fgroup_t; +typedef struct fge_fibril_data fge_fibril_data_t; +typedef struct wu_queue wu_queue_t; typedef errno_t (*hr_wu_t)(void *); +struct fge_fibril_data { + hr_wu_t wu; /* work unit function pointer */ + void *arg; /* work unit function argument */ + hr_fgroup_t *group; /* back-pointer to group */ + ssize_t memslot; /* index to pool bitmap slot */ +}; + +struct wu_queue { + fibril_mutex_t lock; + fibril_condvar_t not_empty; + fibril_condvar_t not_full; + fge_fibril_data_t *fexecs; /* circ-buf memory */ + circ_buf_t cbuf; +}; + +struct hr_fpool { + fibril_mutex_t lock; + bitmap_t bitmap; /* memory slot bitmap */ + wu_queue_t queue; + fid_t *fibrils; + uint8_t *wu_storage; /* pre-allocated pool storage */ + size_t fibril_cnt; + size_t max_wus; + size_t active_groups; + bool stop; + size_t wu_size; + size_t wu_storage_free_count; + fibril_condvar_t all_wus_done; +}; + +struct hr_fgroup { + hr_fpool_t *pool;/* back-pointer to pool */ + size_t wu_cnt;/* upper bound of work units */ + size_t submitted; /* number of submitted jobs */ + size_t reserved_cnt; /* no. of reserved wu storage slots */ + size_t reserved_avail; + size_t *memslots; /* indices to pool bitmap */ + void *own_mem; /* own allocated memory */ + size_t own_used; /* own memory slots used counter */ + errno_t final_errno; /* agreggated errno */ + size_t finished_okay; /* no. of wus that ended with EOK */ + size_t finished_fail; /* no. of wus that ended with != EOK */ + fibril_mutex_t lock; + fibril_condvar_t all_done; +}; + extern hr_fpool_t *hr_fpool_create(size_t, size_t, size_t); extern void hr_fpool_destroy(hr_fpool_t *); extern hr_fgroup_t *hr_fgroup_create(hr_fpool_t *, size_t); From da80de9a46399f701d6045204c960aec68108ea6 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sat, 7 Jun 2025 13:52:34 +0200 Subject: [PATCH 234/324] hr: move state callback to hr_ops_t --- uspace/srv/bd/hr/hr.c | 2 +- uspace/srv/bd/hr/io.c | 2 +- uspace/srv/bd/hr/metadata/native.c | 4 +- uspace/srv/bd/hr/raid0.c | 117 +++++++++++------------ uspace/srv/bd/hr/raid1.c | 143 ++++++++++++++--------------- uspace/srv/bd/hr/raid5.c | 27 +++--- uspace/srv/bd/hr/util.c | 9 +- uspace/srv/bd/hr/var.h | 15 +-- 8 files changed, 157 insertions(+), 162 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 2d4e5d4b63..b2a623b448 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -375,7 +375,7 @@ static void hr_fail_extent_srv(ipc_call_t *icall) fibril_rwlock_write_unlock(&vol->states_lock); fibril_rwlock_read_unlock(&vol->extents_lock); - vol->hr_ops.state_event(vol); + vol->hr_ops.vol_state_eval(vol); async_answer_0(icall, EOK); } diff --git a/uspace/srv/bd/hr/io.c b/uspace/srv/bd/hr/io.c index fd6cb9bdc6..afb079aaa7 100644 --- a/uspace/srv/bd/hr/io.c +++ b/uspace/srv/bd/hr/io.c @@ -59,7 +59,7 @@ errno_t hr_io_worker(void *arg) * other writes, there is no way to rollback. */ if (rc != EOK && (rc != ENOMEM || io->type == HR_BD_WRITE)) - io->vol->state_callback(io->vol, io->extent, rc); + io->vol->hr_ops.ext_state_cb(io->vol, io->extent, rc); return rc; } diff --git a/uspace/srv/bd/hr/metadata/native.c b/uspace/srv/bd/hr/metadata/native.c index b2b93957a4..1814c2b186 100644 --- a/uspace/srv/bd/hr/metadata/native.c +++ b/uspace/srv/bd/hr/metadata/native.c @@ -388,7 +388,7 @@ static errno_t meta_native_save(hr_volume_t *vol, bool with_state_callback) meta_native_encode(md, md_block); rc = meta_native_write_block(ext->svc_id, md_block); if (with_state_callback && rc != EOK) - vol->state_callback(vol, i, rc); + vol->hr_ops.ext_state_cb(vol, i, rc); } fibril_mutex_unlock(&vol->md_lock); @@ -396,7 +396,7 @@ static errno_t meta_native_save(hr_volume_t *vol, bool with_state_callback) fibril_rwlock_read_unlock(&vol->extents_lock); if (with_state_callback) - vol->hr_ops.state_event(vol); + vol->hr_ops.vol_state_eval(vol); free(md_block); return EOK; diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index 0d8f91c307..b6cf484770 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -52,8 +52,6 @@ #include "util.h" #include "var.h" -static void hr_raid0_update_vol_state(hr_volume_t *); -static void hr_raid0_state_callback(hr_volume_t *, size_t, errno_t); static errno_t hr_raid0_bd_op(hr_bd_op_type_t, bd_srv_t *, aoff64_t, size_t, void *, const void *, size_t); @@ -91,7 +89,7 @@ errno_t hr_raid0_create(hr_volume_t *new_volume) return EINVAL; } - hr_raid0_update_vol_state(new_volume); + hr_raid0_vol_state_eval(new_volume); if (new_volume->state != HR_VOL_ONLINE) { HR_NOTE("\"%s\": unusable state, not creating\n", new_volume->devname); @@ -102,8 +100,6 @@ errno_t hr_raid0_create(hr_volume_t *new_volume) new_volume->hr_bds.ops = &hr_raid0_bd_ops; new_volume->hr_bds.sarg = new_volume; - new_volume->state_callback = hr_raid0_state_callback; - return EOK; } @@ -129,11 +125,62 @@ errno_t hr_raid0_init(hr_volume_t *vol) return EOK; } -void hr_raid0_state_event(hr_volume_t *vol) +void hr_raid0_vol_state_eval(hr_volume_t *vol) { HR_DEBUG("%s()", __func__); - hr_raid0_update_vol_state(vol); + fibril_mutex_lock(&vol->md_lock); + + vol->meta_ops->inc_counter(vol->in_mem_md); + /* TODO: save right away */ + + fibril_mutex_unlock(&vol->md_lock); + + fibril_rwlock_read_lock(&vol->states_lock); + + hr_vol_state_t old_state = vol->state; + + for (size_t i = 0; i < vol->extent_no; i++) { + if (vol->extents[i].state != HR_EXT_ONLINE) { + fibril_rwlock_read_unlock(&vol->states_lock); + + if (old_state != HR_VOL_FAULTY) { + fibril_rwlock_write_lock(&vol->states_lock); + hr_update_vol_state(vol, HR_VOL_FAULTY); + fibril_rwlock_write_unlock(&vol->states_lock); + } + return; + } + } + fibril_rwlock_read_unlock(&vol->states_lock); + + if (old_state != HR_VOL_ONLINE) { + fibril_rwlock_write_lock(&vol->states_lock); + hr_update_vol_state(vol, HR_VOL_ONLINE); + fibril_rwlock_write_unlock(&vol->states_lock); + } +} + +void hr_raid0_ext_state_cb(hr_volume_t *vol, size_t extent, errno_t rc) +{ + HR_DEBUG("%s()", __func__); + + if (rc == EOK) + return; + + fibril_rwlock_write_lock(&vol->states_lock); + + switch (rc) { + case ENOENT: + hr_update_ext_state(vol, extent, HR_EXT_MISSING); + break; + default: + hr_update_ext_state(vol, extent, HR_EXT_FAILED); + } + + hr_update_vol_state(vol, HR_VOL_FAULTY); + + fibril_rwlock_write_unlock(&vol->states_lock); } static errno_t hr_raid0_bd_open(bd_srvs_t *bds, bd_srv_t *bd) @@ -191,63 +238,11 @@ static errno_t hr_raid0_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb) return EOK; } -static void hr_raid0_update_vol_state(hr_volume_t *vol) -{ - fibril_mutex_lock(&vol->md_lock); - - vol->meta_ops->inc_counter(vol->in_mem_md); - /* TODO: save right away */ - - fibril_mutex_unlock(&vol->md_lock); - - fibril_rwlock_read_lock(&vol->states_lock); - - hr_vol_state_t old_state = vol->state; - - for (size_t i = 0; i < vol->extent_no; i++) { - if (vol->extents[i].state != HR_EXT_ONLINE) { - fibril_rwlock_read_unlock(&vol->states_lock); - - if (old_state != HR_VOL_FAULTY) { - fibril_rwlock_write_lock(&vol->states_lock); - hr_update_vol_state(vol, HR_VOL_FAULTY); - fibril_rwlock_write_unlock(&vol->states_lock); - } - return; - } - } - fibril_rwlock_read_unlock(&vol->states_lock); - - if (old_state != HR_VOL_ONLINE) { - fibril_rwlock_write_lock(&vol->states_lock); - hr_update_vol_state(vol, HR_VOL_ONLINE); - fibril_rwlock_write_unlock(&vol->states_lock); - } -} - -static void hr_raid0_state_callback(hr_volume_t *vol, size_t extent, errno_t rc) -{ - if (rc == EOK) - return; - - fibril_rwlock_write_lock(&vol->states_lock); - - switch (rc) { - case ENOENT: - hr_update_ext_state(vol, extent, HR_EXT_MISSING); - break; - default: - hr_update_ext_state(vol, extent, HR_EXT_FAILED); - } - - hr_update_vol_state(vol, HR_VOL_FAULTY); - - fibril_rwlock_write_unlock(&vol->states_lock); -} - static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, size_t cnt, void *dst, const void *src, size_t size) { + HR_DEBUG("%s()", __func__); + hr_volume_t *vol = bd->srvs->sarg; errno_t rc; uint64_t phys_block, len; diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index f1d8c3be97..abee80b98c 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -55,8 +55,6 @@ #include "util.h" #include "var.h" -static void hr_raid1_update_vol_state(hr_volume_t *); -static void hr_raid1_ext_state_callback(hr_volume_t *, size_t, errno_t); static size_t hr_raid1_count_good_extents(hr_volume_t *, uint64_t, size_t, uint64_t); static errno_t hr_raid1_bd_op(hr_bd_op_type_t, bd_srv_t *, aoff64_t, size_t, @@ -105,11 +103,9 @@ errno_t hr_raid1_create(hr_volume_t *new_volume) new_volume->hr_bds.ops = &hr_raid1_bd_ops; new_volume->hr_bds.sarg = new_volume; - new_volume->state_callback = hr_raid1_ext_state_callback; - /* force volume state update */ hr_mark_vol_state_dirty(new_volume); - hr_raid1_update_vol_state(new_volume); + hr_raid1_vol_state_eval(new_volume); fibril_rwlock_read_lock(&new_volume->states_lock); hr_vol_state_t state = new_volume->state; @@ -139,81 +135,21 @@ errno_t hr_raid1_init(hr_volume_t *vol) return EOK; } -void hr_raid1_state_event(hr_volume_t *vol) -{ - HR_DEBUG("%s()", __func__); - - hr_raid1_update_vol_state(vol); -} - errno_t hr_raid1_add_hotspare(hr_volume_t *vol, service_id_t hotspare) { HR_DEBUG("%s()", __func__); errno_t rc = hr_util_add_hotspare(vol, hotspare); - hr_raid1_update_vol_state(vol); + hr_raid1_vol_state_eval(vol); return rc; } -static errno_t hr_raid1_bd_open(bd_srvs_t *bds, bd_srv_t *bd) -{ - HR_DEBUG("%s()", __func__); - - hr_volume_t *vol = bd->srvs->sarg; - - atomic_fetch_add_explicit(&vol->open_cnt, 1, memory_order_relaxed); - - return EOK; -} - -static errno_t hr_raid1_bd_close(bd_srv_t *bd) +void hr_raid1_vol_state_eval(hr_volume_t *vol) { HR_DEBUG("%s()", __func__); - hr_volume_t *vol = bd->srvs->sarg; - - atomic_fetch_sub_explicit(&vol->open_cnt, 1, memory_order_relaxed); - - return EOK; -} - -static errno_t hr_raid1_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) -{ - return hr_raid1_bd_op(HR_BD_SYNC, bd, ba, cnt, NULL, NULL, 0); -} - -static errno_t hr_raid1_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, - void *buf, size_t size) -{ - return hr_raid1_bd_op(HR_BD_READ, bd, ba, cnt, buf, NULL, size); -} - -static errno_t hr_raid1_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, - const void *data, size_t size) -{ - return hr_raid1_bd_op(HR_BD_WRITE, bd, ba, cnt, NULL, data, size); -} - -static errno_t hr_raid1_bd_get_block_size(bd_srv_t *bd, size_t *rsize) -{ - hr_volume_t *vol = bd->srvs->sarg; - - *rsize = vol->bsize; - return EOK; -} - -static errno_t hr_raid1_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb) -{ - hr_volume_t *vol = bd->srvs->sarg; - - *rnb = vol->data_blkno; - return EOK; -} - -static void hr_raid1_update_vol_state(hr_volume_t *vol) -{ bool exp = true; /* TODO: could also wrap this */ @@ -270,9 +206,11 @@ static void hr_raid1_update_vol_state(hr_volume_t *vol) } } -static void hr_raid1_ext_state_callback(hr_volume_t *vol, size_t extent, +void hr_raid1_ext_state_cb(hr_volume_t *vol, size_t extent, errno_t rc) { + HR_DEBUG("%s()", __func__); + if (rc == EOK) return; @@ -296,6 +234,61 @@ static void hr_raid1_ext_state_callback(hr_volume_t *vol, size_t extent, fibril_rwlock_write_unlock(&vol->states_lock); } +static errno_t hr_raid1_bd_open(bd_srvs_t *bds, bd_srv_t *bd) +{ + HR_DEBUG("%s()", __func__); + + hr_volume_t *vol = bd->srvs->sarg; + + atomic_fetch_add_explicit(&vol->open_cnt, 1, memory_order_relaxed); + + return EOK; +} + +static errno_t hr_raid1_bd_close(bd_srv_t *bd) +{ + HR_DEBUG("%s()", __func__); + + hr_volume_t *vol = bd->srvs->sarg; + + atomic_fetch_sub_explicit(&vol->open_cnt, 1, memory_order_relaxed); + + return EOK; +} + +static errno_t hr_raid1_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) +{ + return hr_raid1_bd_op(HR_BD_SYNC, bd, ba, cnt, NULL, NULL, 0); +} + +static errno_t hr_raid1_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, + void *buf, size_t size) +{ + return hr_raid1_bd_op(HR_BD_READ, bd, ba, cnt, buf, NULL, size); +} + +static errno_t hr_raid1_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, + const void *data, size_t size) +{ + return hr_raid1_bd_op(HR_BD_WRITE, bd, ba, cnt, NULL, data, size); +} + +static errno_t hr_raid1_bd_get_block_size(bd_srv_t *bd, size_t *rsize) +{ + hr_volume_t *vol = bd->srvs->sarg; + + *rsize = vol->bsize; + return EOK; +} + +static errno_t hr_raid1_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb) +{ + hr_volume_t *vol = bd->srvs->sarg; + + *rnb = vol->data_blkno; + return EOK; +} + static size_t hr_raid1_count_good_extents(hr_volume_t *vol, uint64_t ba, size_t cnt, uint64_t rebuild_blk) { @@ -318,6 +311,8 @@ static size_t hr_raid1_count_good_extents(hr_volume_t *vol, uint64_t ba, static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, size_t cnt, void *data_read, const void *data_write, size_t size) { + HR_DEBUG("%s()", __func__); + hr_volume_t *vol = bd->srvs->sarg; hr_range_lock_t *rl = NULL; errno_t rc; @@ -376,7 +371,7 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, continue; if (rc != EOK) { - hr_raid1_ext_state_callback(vol, i, rc); + hr_raid1_ext_state_cb(vol, i, rc); } else { successful++; break; @@ -457,7 +452,7 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, end: fibril_rwlock_read_unlock(&vol->extents_lock); - hr_raid1_update_vol_state(vol); + hr_raid1_vol_state_eval(vol); return rc; } @@ -564,7 +559,7 @@ static errno_t hr_raid1_rebuild(void *arg) fibril_rwlock_read_unlock(&vol->extents_lock); - hr_raid1_update_vol_state(vol); + hr_raid1_vol_state_eval(vol); if (buf != NULL) free(buf); @@ -689,7 +684,7 @@ static errno_t hr_raid1_restore_blocks(hr_volume_t *vol, size_t rebuild_idx, break; if (rc != ENOMEM) - hr_raid1_ext_state_callback(vol, i, rc); + hr_raid1_ext_state_cb(vol, i, rc); if (i + 1 >= vol->extent_no) { if (rc != ENOMEM) { @@ -704,7 +699,7 @@ static errno_t hr_raid1_restore_blocks(hr_volume_t *vol, size_t rebuild_idx, "failed due to too many failed reads, " "because of not enough memory\n", vol->devname, vol->svc_id); - hr_raid1_ext_state_callback(vol, rebuild_idx, + hr_raid1_ext_state_cb(vol, rebuild_idx, ENOMEM); } @@ -722,7 +717,7 @@ static errno_t hr_raid1_restore_blocks(hr_volume_t *vol, size_t rebuild_idx, * * XXX: for now we do */ - hr_raid1_ext_state_callback(vol, rebuild_idx, rc); + hr_raid1_ext_state_cb(vol, rebuild_idx, rc); HR_ERROR("rebuild on \"%s\" (%" PRIun "), failed due to " "the rebuilt extent no. %zu WRITE (rc: %s)\n", diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 3e6ed3e52e..e9b9fe353f 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -56,7 +56,6 @@ static errno_t hr_raid5_vol_usable(hr_volume_t *); static ssize_t hr_raid5_get_bad_ext(hr_volume_t *); static errno_t hr_raid5_update_vol_state(hr_volume_t *); -static void hr_raid5_handle_extent_error(hr_volume_t *, size_t, errno_t); static void xor(void *, const void *, size_t); static errno_t hr_raid5_read_degraded(hr_volume_t *, uint64_t, uint64_t, @@ -147,7 +146,7 @@ errno_t hr_raid5_init(hr_volume_t *vol) return EOK; } -void hr_raid5_state_event(hr_volume_t *vol) +void hr_raid5_vol_state_eval(hr_volume_t *vol) { fibril_mutex_lock(&vol->lock); fibril_rwlock_write_lock(&vol->states_lock); @@ -188,6 +187,15 @@ errno_t hr_raid5_add_hotspare(hr_volume_t *vol, service_id_t hotspare) return rc; } +void hr_raid5_ext_state_cb(hr_volume_t *vol, size_t extent, + errno_t rc) +{ + if (rc == ENOENT) + hr_update_ext_state(vol, extent, HR_EXT_MISSING); + else if (rc != EOK) + hr_update_ext_state(vol, extent, HR_EXT_FAILED); +} + static errno_t hr_raid5_bd_open(bd_srvs_t *bds, bd_srv_t *bd) { HR_DEBUG("%s()\n", __func__); @@ -300,15 +308,6 @@ static errno_t hr_raid5_update_vol_state(hr_volume_t *vol) } } -static void hr_raid5_handle_extent_error(hr_volume_t *vol, size_t extent, - errno_t rc) -{ - if (rc == ENOENT) - hr_update_ext_state(vol, extent, HR_EXT_MISSING); - else if (rc != EOK) - hr_update_ext_state(vol, extent, HR_EXT_FAILED); -} - static void xor(void *dst, const void *src, size_t size) { size_t i; @@ -647,7 +646,7 @@ static errno_t hr_raid5_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, if (rc == ENOMEM) goto error; - hr_raid5_handle_extent_error(vol, extent, rc); + hr_raid5_ext_state_cb(vol, extent, rc); if (rc != EOK) { rc = hr_raid5_update_vol_state(vol); @@ -801,7 +800,7 @@ static errno_t hr_raid5_rebuild(void *arg) rc = block_read_direct(vol->extents[i].svc_id, ba, cnt, buf); if (rc != EOK) { - hr_raid5_handle_extent_error(vol, i, rc); + hr_raid5_ext_state_cb(vol, i, rc); HR_ERROR("rebuild on \"%s\" (%" PRIun "), " "failed due to a failed ONLINE extent, " "number %zu\n", @@ -817,7 +816,7 @@ static errno_t hr_raid5_rebuild(void *arg) rc = block_write_direct(rebuild_ext->svc_id, ba, cnt, xorbuf); if (rc != EOK) { - hr_raid5_handle_extent_error(vol, bad, rc); + hr_raid5_ext_state_cb(vol, bad, rc); HR_ERROR("rebuild on \"%s\" (%" PRIun "), failed due to " "the rebuilt extent number %zu failing\n", vol->devname, vol->svc_id, bad); diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index b61f7a235b..be737b5023 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -97,12 +97,14 @@ errno_t hr_create_vol_struct(hr_volume_t **rvol, hr_level_t level, case HR_LVL_0: vol->hr_ops.create = hr_raid0_create; vol->hr_ops.init = hr_raid0_init; - vol->hr_ops.state_event = hr_raid0_state_event; + vol->hr_ops.vol_state_eval = hr_raid0_vol_state_eval; + vol->hr_ops.ext_state_cb = hr_raid0_ext_state_cb; break; case HR_LVL_1: vol->hr_ops.create = hr_raid1_create; vol->hr_ops.init = hr_raid1_init; - vol->hr_ops.state_event = hr_raid1_state_event; + vol->hr_ops.vol_state_eval = hr_raid1_vol_state_eval; + vol->hr_ops.ext_state_cb = hr_raid1_ext_state_cb; if (meta_flags & HR_METADATA_HOTSPARE_SUPPORT) vol->hr_ops.add_hotspare = hr_raid1_add_hotspare; break; @@ -110,7 +112,8 @@ errno_t hr_create_vol_struct(hr_volume_t **rvol, hr_level_t level, case HR_LVL_5: vol->hr_ops.create = hr_raid5_create; vol->hr_ops.init = hr_raid5_init; - vol->hr_ops.state_event = hr_raid5_state_event; + vol->hr_ops.vol_state_eval = hr_raid5_vol_state_eval; + vol->hr_ops.ext_state_cb = hr_raid5_ext_state_cb; if (meta_flags & HR_METADATA_HOTSPARE_SUPPORT) vol->hr_ops.add_hotspare = hr_raid5_add_hotspare; break; diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index 04519a2613..f61cac6ed9 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -57,8 +57,9 @@ typedef struct hr_superblock_ops hr_superblock_ops_t; typedef struct hr_ops { errno_t (*create)(hr_volume_t *); errno_t (*init)(hr_volume_t *); - void (*state_event)(hr_volume_t *); errno_t (*add_hotspare)(hr_volume_t *, service_id_t); + void (*vol_state_eval)(hr_volume_t *); + void (*ext_state_cb)(hr_volume_t *, size_t, errno_t); } hr_ops_t; typedef struct hr_volume { @@ -103,7 +104,6 @@ typedef struct hr_volume { _Atomic uint64_t rebuild_blk; /* rebuild position */ _Atomic int open_cnt; /* open/close() counter */ hr_vol_state_t state; /* volume state */ - void (*state_callback)(hr_volume_t *, size_t, errno_t); } hr_volume_t; typedef enum { @@ -135,13 +135,16 @@ extern errno_t hr_raid0_init(hr_volume_t *); extern errno_t hr_raid1_init(hr_volume_t *); extern errno_t hr_raid5_init(hr_volume_t *); -extern void hr_raid0_state_event(hr_volume_t *); -extern void hr_raid1_state_event(hr_volume_t *); -extern void hr_raid5_state_event(hr_volume_t *); - extern errno_t hr_raid1_add_hotspare(hr_volume_t *, service_id_t); extern errno_t hr_raid5_add_hotspare(hr_volume_t *, service_id_t); +extern void hr_raid0_vol_state_eval(hr_volume_t *); +extern void hr_raid1_vol_state_eval(hr_volume_t *); +extern void hr_raid5_vol_state_eval(hr_volume_t *); + +extern void hr_raid0_ext_state_cb(hr_volume_t *, size_t, errno_t); +extern void hr_raid1_ext_state_cb(hr_volume_t *, size_t, errno_t); +extern void hr_raid5_ext_state_cb(hr_volume_t *, size_t, errno_t); #endif /** @} From d482b050e50ba513e663660d92e1d56290aacd5a Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 9 Jun 2025 14:41:28 +0200 Subject: [PATCH 235/324] hrctl: add synopsis to usage message --- uspace/app/hrctl/hrctl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index 4f55107cdd..12438680e8 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -52,7 +52,8 @@ static errno_t fill_config_devs(int, char **, hr_config_t *); static errno_t get_vol_configs_from_sif(const char *, hr_config_t **, size_t *); static const char usage_str[] = - "Usage: hrctl [OPTION]...\n" + NAME ": HelenOS RAID configuration and management utility.\n" + "Usage: " NAME " [OPTION]...\n" "\n" "Options:\n" " -h, --help Display this message and exit.\n" From 431b513a6e48dd61f02244447a7173fd175fa1f7 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 9 Jun 2025 14:41:42 +0200 Subject: [PATCH 236/324] hrctl: also parse levels as words --- uspace/app/hrctl/hrctl.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index 12438680e8..c1453effec 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -77,6 +77,12 @@ static const char usage_str[] = "\n" " -s, --state Display state of active volumes.\n" "\n" + "level can be one of:\n" + " 0 | stripe | striping |\n" + " 1 | mirror | mirroring |\n" + " 4 | parity_dedicated |\n" + " 5 | parity | parity_distributed\n" + "\n" "Example usage:\n" "\t\thrctl --create hr0 --level 5 disk1 disk2 disk3\n" "\t\thrctl -c hr0 -l 5 disk1 disk2 disk3\n" @@ -310,13 +316,26 @@ static int create_from_argv(hr_t *hr, int argc, char **argv) } const char *level_str = argv[optind++]; - if (str_size(level_str) != 1 && !isdigit(level_str[0])) { - printf(NAME ": unknown level \"%s\"\n", level_str); - goto error; + if (str_size(level_str) == 1 && isdigit(level_str[0])) { + vol_config->level = strtol(level_str, NULL, 10); + } else { + if (str_cmp(level_str, "mirror") == 0 || + str_cmp(level_str, "mirroring") == 0) { + vol_config->level = HR_LVL_1; + } else if (str_cmp(level_str, "stripe") == 0 || + str_cmp(level_str, "striping") == 0) { + vol_config->level = HR_LVL_0; + } else if (str_cmp(level_str, "parity") == 0 || + str_cmp(level_str, "parity_distributed") == 0) { + vol_config->level = HR_LVL_5; + } else if (str_cmp(level_str, "parity_dedicated") == 0) { + vol_config->level = HR_LVL_4; + } else { + printf(NAME ": unknown level \"%s\"\n", level_str); + goto error; + } } - vol_config->level = strtol(level_str, NULL, 10); - errno_t rc = fill_config_devs(argc, argv, vol_config); if (rc != EOK) goto error; From e0bbecb7cb52d3499d94395fa598579d09a6de5d Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 9 Jun 2025 22:01:03 +0200 Subject: [PATCH 237/324] hr: move state printing to hrctl One IPC call is for short volume states printing and other one for specific volume detailed info printing. --- uspace/app/hrctl/hrctl.c | 276 +++++++++++++++++++++++------ uspace/app/hrctl/meson.build | 2 +- uspace/lib/device/include/hr.h | 36 ++-- uspace/lib/device/include/ipc/hr.h | 3 +- uspace/lib/device/src/hr.c | 186 +++++++++---------- uspace/srv/bd/hr/hr.c | 112 +++++++++--- 6 files changed, 413 insertions(+), 202 deletions(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index c1453effec..903611138b 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -33,6 +33,7 @@ * @file */ +#include #include #include #include @@ -50,6 +51,16 @@ static void usage(void); static errno_t fill_config_devs(int, char **, hr_config_t *); static errno_t get_vol_configs_from_sif(const char *, hr_config_t **, size_t *); +static int create_from_config(hr_t *, const char *); +static int create_from_argv(hr_t *, int, char **); +static int handle_create(hr_t *, int, char **); +static int assemble_from_config(hr_t *, const char *); +static int assemble_from_argv(hr_t *, int, char **); +static int handle_assemble(hr_t *, int, char **); +static int handle_disassemble(hr_t *, int, char **); +static int handle_modify(hr_t *, int, char **); +static errno_t print_vol_info(hr_vol_info_t *); +static int handle_state(hr_t *, int, char **); static const char usage_str[] = NAME ": HelenOS RAID configuration and management utility.\n" @@ -75,7 +86,7 @@ static const char usage_str[] = " -f, --fail index fail an extent (DANGEROUS), or\n" " -h, --hotspare device add hotspare.\n" "\n" - " -s, --state Display state of active volumes.\n" + " -s, --state [volume] Display state of active volume(s).\n" "\n" "level can be one of:\n" " 0 | stripe | striping |\n" @@ -107,6 +118,68 @@ static const char usage_str[] = "\t- volume name must be shorter than 32 characters\n" "\t- automatic assembly and disassembly on nested volumes is UNDEFINED!\n"; +int main(int argc, char **argv) +{ + int rc = EXIT_SUCCESS; + hr_t *hr = NULL; + + if (argc < 2) { + rc = EXIT_FAILURE; + goto end; + } + + rc = hr_sess_init(&hr); + if (rc != EOK) { + printf(NAME ": hr server session init failed: %s\n", + str_error(rc)); + return EXIT_FAILURE; + } + + optreset = 1; + optind = 0; + + struct option const top_level_opts[] = { + { "help", no_argument, 0, 'h' }, + { "create", no_argument, 0, 'c' }, + { "assemble", no_argument, 0, 'a' }, + { "disassemble", no_argument, 0, 'd' }, + { "modify", no_argument, 0, 'm' }, + { "state", no_argument, 0, 's' }, + { 0, 0, 0, 0 } + }; + + int c = getopt_long(argc, argv, "hcadms", top_level_opts, NULL); + switch (c) { + case 'h': + usage(); + goto end; + case 'c': + rc = handle_create(hr, argc, argv); + goto end; + case 'a': + rc = handle_assemble(hr, argc, argv); + goto end; + case 'd': + rc = handle_disassemble(hr, argc, argv); + goto end; + case 'm': + rc = handle_modify(hr, argc, argv); + goto end; + case 's': + rc = handle_state(hr, argc, argv); + goto end; + default: + goto end; + } + +end: + hr_sess_destroy(hr); + + if (rc != EXIT_SUCCESS) + printf(NAME ": use --help to see usage\n"); + return rc; +} + static void usage(void) { printf("%s", usage_str); @@ -552,80 +625,165 @@ static int handle_modify(hr_t *hr, int argc, char **argv) return EXIT_SUCCESS; } -static int handle_state(hr_t *hr, int argc, char **argv) +static errno_t print_vol_info(hr_vol_info_t *info) { - (void)argc; - (void)argv; + errno_t rc; + size_t i; + hr_extent_t *ext; + const char *devname; + + printf("volume: \"%s\" (%" PRIun ")\n", info->devname, info->svc_id); + + printf("| metadata type: %s\n", + hr_get_metadata_type_str(info->meta_type)); + printf("| level: %s\n", hr_get_level_str(info->level)); + if (info->layout != HR_RLQ_NONE) + printf("| layout: %s\n", + hr_get_layout_str(info->layout)); + + if (info->strip_size > 0) { + if (info->strip_size < 1024) { + printf("| strip size: %" PRIu32 "B\n", + info->strip_size); + } else { + printf("| strip size: %" PRIu32 "KiB\n", + info->strip_size / 1024); + } + } + + printf("| no. of extents: %zu\n", info->extent_no); + printf("|no. of hotspares: %zu\n", info->hotspare_no); + printf("|number of blocks: %" PRIu64 "\n", info->data_blkno); + printf("| block size: %zuB\n", info->bsize); - errno_t rc = hr_print_state(hr); + capa_spec_t capa; + char *scapa = NULL; + capa_from_blocks(info->data_blkno, info->bsize, &capa); + capa_simplify(&capa); + rc = capa_format(&capa, &scapa); if (rc != EOK) { - printf(NAME ": state printing failed: %s\n", str_error(rc)); - return EXIT_FAILURE; + printf(NAME ": failed to format capacity: %s\n", str_error(rc)); + return rc; } - return EXIT_SUCCESS; -} + printf("| volume capacity: %s\n", scapa); -int main(int argc, char **argv) -{ - int rc = EXIT_SUCCESS; - hr_t *hr = NULL; + free(scapa); - if (argc < 2) { - rc = EXIT_FAILURE; - goto end; + printf("| state: %s\n", hr_get_vol_state_str(info->state)); + printf("| extents:\n"); + + for (i = 0; i < info->extent_no; i++) { + ext = &info->extents[i]; + char *tmpname = NULL; + if (ext->state == HR_EXT_MISSING || ext->state == HR_EXT_NONE) { + devname = "MISSING"; + } else { + rc = loc_service_get_name(ext->svc_id, &tmpname); + if (rc != EOK) + devname = "MISSING"; + else + devname = tmpname; + } + printf("| %zu %s\n", i, hr_get_ext_state_str(ext->state)); + printf("| %s\n", devname); + if (tmpname != NULL) + free(tmpname); } - rc = hr_sess_init(&hr); - if (rc != EOK) { - printf(NAME ": hr server session init failed: %s\n", - str_error(rc)); - return EXIT_FAILURE; + if (info->hotspare_no == 0) + return EOK; + + printf("| hotspares:\n"); + for (i = 0; i < info->hotspare_no; i++) { + ext = &info->hotspares[i]; + char *tmpname; + if (ext->state == HR_EXT_MISSING || ext->state == HR_EXT_NONE) { + devname = "MISSING"; + } else { + rc = loc_service_get_name(ext->svc_id, &tmpname); + if (rc != EOK) + devname = "MISSING"; + else + devname = tmpname; + } + printf("| %zu %s\n", i, hr_get_ext_state_str(ext->state)); + printf("| %s\n", devname); + if (tmpname != NULL) + free(tmpname); } - optreset = 1; - optind = 0; + return EOK; +} - struct option const top_level_opts[] = { - { "help", no_argument, 0, 'h' }, - { "create", no_argument, 0, 'c' }, - { "assemble", no_argument, 0, 'a' }, - { "disassemble", no_argument, 0, 'd' }, - { "modify", no_argument, 0, 'm' }, - { "state", no_argument, 0, 's' }, - { 0, 0, 0, 0 } - }; +static int handle_state(hr_t *hr, int argc, char **argv) +{ + errno_t rc; + size_t cnt; + hr_pair_vol_state_t *pairs = NULL; + char *devname; - int c = getopt_long(argc, argv, "hcadms", top_level_opts, NULL); - switch (c) { - case 'h': - usage(); - goto end; - case 'c': - rc = handle_create(hr, argc, argv); - goto end; - case 'a': - rc = handle_assemble(hr, argc, argv); - goto end; - case 'd': - rc = handle_disassemble(hr, argc, argv); - goto end; - case 'm': - rc = handle_modify(hr, argc, argv); - goto end; - case 's': - rc = handle_state(hr, argc, argv); - goto end; - default: - goto end; + /* print state of all volumes */ + if (optind >= argc) { + rc = hr_get_vol_states(hr, &pairs, &cnt); + if (rc != EOK) { + printf(NAME ": failed getting state of volumes: %s\n", + str_error(rc)); + return EXIT_FAILURE; + } + + if (cnt == 0) { + printf(NAME ": no active volumes\n"); + return EXIT_SUCCESS; + } + + for (size_t i = 0; i < cnt; i++) { + service_id_t svc_id = pairs[i].svc_id; + hr_vol_state_t state = pairs[i].state; + rc = loc_service_get_name(svc_id, &devname); + if (rc != EOK) { + printf(NAME ": getting service name failed: " + "%s\n", str_error(rc)); + return EXIT_FAILURE; + } + printf("volume \"%s\" (%" PRIun ") %s\n", devname, + svc_id, hr_get_vol_state_str(state)); + + free(devname); + } + free(pairs); + + return EXIT_SUCCESS; } -end: - hr_sess_destroy(hr); + /* print volume info of requested volumes */ + while (optind < argc) { + service_id_t svc_id; + devname = argv[optind++]; + rc = loc_service_get_id(devname, &svc_id, 0); + if (rc != EOK) { + printf(NAME ": getting service id of \"%s\" failed: " + "%s\n", devname, str_error(rc)); + return EXIT_FAILURE; + } - if (rc != EXIT_SUCCESS) - printf(NAME ": use --help to see usage\n"); - return rc; + hr_vol_info_t info; + rc = hr_get_vol_info(hr, svc_id, &info); + if (rc != EOK) { + printf(NAME ": getting volume info failed: %s\n", + str_error(rc)); + return EXIT_FAILURE; + } + + rc = print_vol_info(&info); + if (rc != EOK) { + printf(NAME ": volume info printing failed: %s\n", + str_error(rc)); + return EXIT_FAILURE; + } + } + + return EXIT_SUCCESS; } /** @} diff --git a/uspace/app/hrctl/meson.build b/uspace/app/hrctl/meson.build index e8b21888d3..5185436c12 100644 --- a/uspace/app/hrctl/meson.build +++ b/uspace/app/hrctl/meson.build @@ -1,5 +1,5 @@ # -# Copyright (c) 2024 Miroslav Cimerman +# Copyright (c) 2025 Miroslav Cimerman # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index 338eb2159d..aa8e4edae3 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -81,6 +81,14 @@ typedef enum hr_ext_state { HR_EXT_HOTSPARE } hr_ext_state_t; +typedef enum { + HR_METADATA_NATIVE = 0, + HR_METADATA_GEOM_MIRROR, + HR_METADATA_GEOM_STRIPE, + HR_METADATA_SOFTRAID, + HR_METADATA_LAST_DUMMY +} hr_metadata_type_t; + typedef struct hr { async_sess_t *sess; } hr_t; @@ -97,28 +105,28 @@ typedef struct hr_extent { hr_ext_state_t state; } hr_extent_t; +typedef struct hr_pair_vol_state { + service_id_t svc_id; + hr_vol_state_t state; +} hr_pair_vol_state_t; + typedef struct hr_vol_info { + char devname[HR_DEVNAME_LEN]; + service_id_t svc_id; + hr_level_t level; hr_extent_t extents[HR_MAX_EXTENTS]; hr_extent_t hotspares[HR_MAX_HOTSPARES]; size_t extent_no; size_t hotspare_no; - service_id_t svc_id; - hr_level_t level; - uint64_t nblocks; + uint64_t data_blkno; uint32_t strip_size; size_t bsize; hr_vol_state_t state; - uint8_t layout; + hr_layout_t layout; + hr_metadata_type_t meta_type; + /* TODO: add rebuild pos */ } hr_vol_info_t; -typedef enum { - HR_METADATA_NATIVE = 0, - HR_METADATA_GEOM_MIRROR, - HR_METADATA_GEOM_STRIPE, - HR_METADATA_SOFTRAID, - HR_METADATA_LAST_DUMMY -} hr_metadata_type_t; - extern errno_t hr_sess_init(hr_t **); extern void hr_sess_destroy(hr_t *); extern errno_t hr_create(hr_t *, hr_config_t *); @@ -128,10 +136,12 @@ extern errno_t hr_stop(hr_t *, const char *); extern errno_t hr_stop_all(hr_t *); extern errno_t hr_fail_extent(hr_t *, const char *, unsigned long); extern errno_t hr_add_hotspare(hr_t *, const char *, const char *); -extern errno_t hr_print_state(hr_t *); +extern errno_t hr_get_vol_states(hr_t *, hr_pair_vol_state_t **, size_t *); +extern errno_t hr_get_vol_info(hr_t *, service_id_t, hr_vol_info_t *); extern const char *hr_get_vol_state_str(hr_vol_state_t); extern const char *hr_get_ext_state_str(hr_ext_state_t); extern const char *hr_get_layout_str(hr_layout_t); +extern const char *hr_get_level_str(hr_level_t); extern const char *hr_get_metadata_type_str(hr_metadata_type_t); #endif diff --git a/uspace/lib/device/include/ipc/hr.h b/uspace/lib/device/include/ipc/hr.h index 3872675062..b7d659dc24 100644 --- a/uspace/lib/device/include/ipc/hr.h +++ b/uspace/lib/device/include/ipc/hr.h @@ -45,7 +45,8 @@ typedef enum { HR_STOP_ALL, HR_FAIL_EXTENT, HR_ADD_HOTSPARE, - HR_STATUS + HR_GET_VOL_STATES, + HR_GET_VOL_INFO } hr_request_t; #endif diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index fb2f0e6f87..fe8b6c5ed2 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -208,89 +208,6 @@ errno_t hr_auto_assemble(hr_t *hr, size_t *rassembled_cnt) return rc; } -static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info) -{ - errno_t rc; - size_t i; - char *devname; - hr_extent_t *ext; - - printf("--- vol %zu ---\n", index); - - printf("svc_id: %" PRIun "\n", vol_info->svc_id); - - rc = loc_service_get_name(vol_info->svc_id, &devname); - if (rc != EOK) - return rc; - printf("devname: %s\n", devname); - - printf("state: %s\n", hr_get_vol_state_str(vol_info->state)); - - printf("level: %d\n", vol_info->level); - if (vol_info->level == HR_LVL_4 || vol_info->level == HR_LVL_5) { - printf("layout: %s\n", - hr_get_layout_str(vol_info->layout)); - } - if (vol_info->level == HR_LVL_0 || vol_info->level == HR_LVL_4) { - if (vol_info->strip_size / 1024 < 1) - printf("strip size in bytes: %" PRIu32 "\n", - vol_info->strip_size); - else - printf("strip size: %" PRIu32 "K\n", - vol_info->strip_size / 1024); - } - printf("size in bytes: %" PRIu64 "MiB\n", - vol_info->nblocks * vol_info->bsize / 1024 / 1024); - printf("size in blocks: %" PRIu64 "\n", vol_info->nblocks); - printf("block size: %zu\n", vol_info->bsize); - - if (vol_info->level == HR_LVL_4) - printf("extents: [P] [state] [index] [devname]\n"); - else - printf("extents: [state] [index] [devname]\n"); - for (i = 0; i < vol_info->extent_no; i++) { - ext = &vol_info->extents[i]; - if (ext->state == HR_EXT_MISSING || ext->state == HR_EXT_NONE) { - devname = (char *) "MISSING-devname"; - } else { - rc = loc_service_get_name(ext->svc_id, &devname); - if (rc != EOK) { - printf("loc_service_get_name() failed, skipping...\n"); - continue; - } - } - if (vol_info->level == HR_LVL_4) { - if ((i == 0 && vol_info->layout == HR_RLQ_RAID4_0) || - (i == vol_info->extent_no - 1 && - vol_info->layout == HR_RLQ_RAID4_N)) - printf(" P %s %zu %s\n", hr_get_ext_state_str(ext->state), i, devname); - else - printf(" %s %zu %s\n", hr_get_ext_state_str(ext->state), i, devname); - } else { - printf(" %s %zu %s\n", hr_get_ext_state_str(ext->state), i, devname); - } - } - - if (vol_info->hotspare_no == 0) - return EOK; - - printf("hotspares: [state] [index] [devname]\n"); - for (i = 0; i < vol_info->hotspare_no; i++) { - ext = &vol_info->hotspares[i]; - if (ext->state == HR_EXT_MISSING) { - devname = (char *) "MISSING-devname"; - } else { - rc = loc_service_get_name(ext->svc_id, &devname); - if (rc != EOK) - return rc; - } - printf(" %s %zu %s\n", - hr_get_ext_state_str(ext->state), i, devname); - } - - return EOK; -} - /** Stop/deactivate volume. * * @param hr Server session @@ -407,19 +324,21 @@ errno_t hr_add_hotspare(hr_t *hr, const char *volume_name, const char *hotspare) return rc; } -/** Print state of volumes. +/** Get state of volumes. * - * @param hr Server session + * @param hr Server session + * @param rpairs Place to store pointer to (service id, vol state) pairs + * @param rcnt Place to store pair count * * @return EOK on success or an error code */ -errno_t hr_print_state(hr_t *hr) +errno_t hr_get_vol_states(hr_t *hr, hr_pair_vol_state_t **rpairs, size_t *rcnt) { errno_t rc, retval; async_exch_t *exch; aid_t req; - size_t size, i; - hr_vol_info_t *vols = NULL; + size_t cnt, i; + hr_pair_vol_state_t *pairs = NULL; exch = async_exchange_begin(hr->sess); if (exch == NULL) { @@ -427,24 +346,23 @@ errno_t hr_print_state(hr_t *hr) goto error; } - req = async_send_0(exch, HR_STATUS, NULL); - rc = async_data_read_start(exch, &size, sizeof(size_t)); + req = async_send_0(exch, HR_GET_VOL_STATES, NULL); + rc = async_data_read_start(exch, &cnt, sizeof(size_t)); if (rc != EOK) { async_exchange_end(exch); async_forget(req); return rc; } - vols = calloc(size, sizeof(hr_vol_info_t)); - if (vols == NULL) { + pairs = calloc(cnt, sizeof(*pairs)); + if (pairs == NULL) { async_exchange_end(exch); async_forget(req); return ENOMEM; } - for (i = 0; i < size; i++) { - rc = async_data_read_start(exch, &vols[i], - sizeof(hr_vol_info_t)); + for (i = 0; i < cnt; i++) { + rc = async_data_read_start(exch, &pairs[i], sizeof(*pairs)); if (rc != EOK) { async_exchange_end(exch); async_forget(req); @@ -459,20 +377,60 @@ errno_t hr_print_state(hr_t *hr) goto error; } - if (size == 0) { - printf("no active volumes\n"); + if (rpairs != NULL) + *rpairs = pairs; + if (rcnt != NULL) + *rcnt = cnt; + return EOK; + +error: + if (pairs != NULL) + free(pairs); + return rc; +} + +/** Get volume info. + * + * @param hr Server session + * @param svc_id Service id of volume + * @param rinfo Place to store volume info + * + * @return EOK on success or an error code + */ +errno_t hr_get_vol_info(hr_t *hr, service_id_t svc_id, hr_vol_info_t *rinfo) +{ + errno_t rc, retval; + async_exch_t *exch; + aid_t req; + + exch = async_exchange_begin(hr->sess); + if (exch == NULL) { + rc = EINVAL; + goto error; + } + + req = async_send_0(exch, HR_GET_VOL_INFO, NULL); + rc = async_data_write_start(exch, &svc_id, sizeof(svc_id)); + if (rc != EOK) { + async_exchange_end(exch); + async_forget(req); + return rc; + } + + rc = async_data_read_start(exch, rinfo, sizeof(*rinfo)); + async_exchange_end(exch); + if (rc != EOK) { + async_forget(req); goto error; } - for (i = 0; i < size; i++) { - rc = print_vol_info(i, &vols[i]); - if (rc != EOK) - goto error; + async_wait_for(req, &retval); + if (retval != EOK) { + rc = retval; + goto error; } error: - if (vols != NULL) - free(vols); return rc; } @@ -554,6 +512,28 @@ const char *hr_get_layout_str(hr_layout_t layout) } } +/** Get volume level string. + * + * @param level Levelvalue + * + * @return Level string + */ +const char *hr_get_level_str(hr_level_t level) +{ + switch (level) { + case HR_LVL_0: + return "stripe (RAID 0)"; + case HR_LVL_1: + return "mirror (RAID 1)"; + case HR_LVL_4: + return "dedicated parity (RAID 4)"; + case HR_LVL_5: + return "distributed parity (RAID 5)"; + default: + return "Invalid RAID level"; + } +} + /** Get volume metadata type string. * * @param type Metadata type value diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index b2a623b448..25f16ff92e 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -58,7 +58,7 @@ static void hr_auto_assemble_srv(ipc_call_t *); static void hr_stop_srv(ipc_call_t *); static void hr_stop_all_srv(ipc_call_t *); static void hr_add_hotspare_srv(ipc_call_t *); -static void hr_print_state_srv(ipc_call_t *); +static void hr_get_vol_states_srv(ipc_call_t *); static void hr_ctl_conn(ipc_call_t *); static void hr_client_conn(ipc_call_t *, void *); @@ -415,17 +415,17 @@ static void hr_add_hotspare_srv(ipc_call_t *icall) async_answer_0(icall, rc); } -/** Volume state printing (server). +/** Send volume states. * - * Prints info about all active volumes. + * Sends the client pairs of (volume service_id, state). */ -static void hr_print_state_srv(ipc_call_t *icall) +static void hr_get_vol_states_srv(ipc_call_t *icall) { HR_DEBUG("%s()", __func__); errno_t rc; size_t vol_cnt = 0; - hr_vol_info_t info; + hr_pair_vol_state_t pair; ipc_call_t call; size_t size; @@ -438,7 +438,7 @@ static void hr_print_state_srv(ipc_call_t *icall) goto error; } - if (size != sizeof(size_t)) { + if (size != sizeof(vol_cnt)) { rc = EINVAL; goto error; } @@ -448,33 +448,20 @@ static void hr_print_state_srv(ipc_call_t *icall) goto error; list_foreach(hr_volumes, lvolumes, hr_volume_t, vol) { - memcpy(info.extents, vol->extents, - sizeof(hr_extent_t) * HR_MAX_EXTENTS); - memcpy(info.hotspares, vol->hotspares, - sizeof(hr_extent_t) * HR_MAX_HOTSPARES); - info.svc_id = vol->svc_id; - info.extent_no = vol->extent_no; - info.hotspare_no = vol->hotspare_no; - info.level = vol->level; - /* print usable number of blocks */ - /* TODO: change to data_blkno */ - info.nblocks = vol->data_blkno; - info.strip_size = vol->strip_size; - info.bsize = vol->bsize; - info.state = vol->state; - info.layout = vol->layout; + pair.svc_id = vol->svc_id; + pair.state = vol->state; if (!async_data_read_receive(&call, &size)) { rc = EREFUSED; goto error; } - if (size != sizeof(hr_vol_info_t)) { + if (size != sizeof(pair)) { rc = EINVAL; goto error; } - rc = async_data_read_finalize(&call, &info, size); + rc = async_data_read_finalize(&call, &pair, size); if (rc != EOK) goto error; } @@ -488,6 +475,78 @@ static void hr_print_state_srv(ipc_call_t *icall) async_answer_0(icall, rc); } +/** Send volume info. + * + * Sends the client volume info. + */ +static void hr_get_vol_info_srv(ipc_call_t *icall) +{ + HR_DEBUG("%s()", __func__); + + errno_t rc; + size_t size; + ipc_call_t call; + service_id_t svc_id; + hr_vol_info_t info; + hr_volume_t *vol; + + if (!async_data_write_receive(&call, &size)) { + rc = EREFUSED; + goto error; + } + + if (size != sizeof(service_id_t)) { + rc = EINVAL; + goto error; + } + + rc = async_data_write_finalize(&call, &svc_id, size); + if (rc != EOK) + goto error; + + vol = hr_get_volume(svc_id); + if (vol == NULL) { + rc = ENOENT; + goto error; + } + + memcpy(info.extents, vol->extents, + sizeof(hr_extent_t) * HR_MAX_EXTENTS); + memcpy(info.hotspares, vol->hotspares, + sizeof(hr_extent_t) * HR_MAX_HOTSPARES); + info.svc_id = vol->svc_id; + info.extent_no = vol->extent_no; + info.hotspare_no = vol->hotspare_no; + info.level = vol->level; + info.data_blkno = vol->data_blkno; + info.strip_size = vol->strip_size; + info.bsize = vol->bsize; + info.state = vol->state; + info.layout = vol->layout; + info.meta_type = vol->meta_ops->get_type(); + memcpy(info.devname, vol->devname, HR_DEVNAME_LEN); + + if (!async_data_read_receive(&call, &size)) { + rc = EREFUSED; + goto error; + } + + if (size != sizeof(info)) { + rc = EINVAL; + goto error; + } + + rc = async_data_read_finalize(&call, &info, size); + if (rc != EOK) + goto error; + + async_answer_0(icall, EOK); + return; +error: + async_answer_0(&call, rc); + async_answer_0(icall, rc); +} + /** HelenRAID server control IPC methods crossroad. */ static void hr_ctl_conn(ipc_call_t *icall) @@ -528,8 +587,11 @@ static void hr_ctl_conn(ipc_call_t *icall) case HR_ADD_HOTSPARE: hr_add_hotspare_srv(&call); break; - case HR_STATUS: - hr_print_state_srv(&call); + case HR_GET_VOL_STATES: + hr_get_vol_states_srv(&call); + break; + case HR_GET_VOL_INFO: + hr_get_vol_info_srv(&call); break; default: async_answer_0(&call, EINVAL); From e2a8fd29503940cc3a61c5926c628938f77e5ec2 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 9 Jun 2025 22:02:26 +0200 Subject: [PATCH 238/324] hr: try automatic assembly on server start --- uspace/srv/bd/hr/hr.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 25f16ff92e..4a0964a125 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -651,6 +651,11 @@ int main(int argc, char **argv) return EEXIST; } + printf("%s: Trying automatic assembly.\n", NAME); + size_t assembled = 0; + (void)hr_util_try_assemble(NULL, &assembled); + printf("%s: Assembled %zu volume(s).\n", NAME, assembled); + printf("%s: Accepting connections.\n", NAME); task_retval(0); async_manager(); From f34568c4fa35a4ae2b4da66fa4bbc2c6839f55d2 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 9 Jun 2025 22:42:55 +0200 Subject: [PATCH 239/324] hr: print % done of REBUILD operation --- uspace/app/hrctl/hrctl.c | 10 +++++++++- uspace/lib/device/include/hr.h | 1 + uspace/srv/bd/hr/hr.c | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index 903611138b..d33b8fe431 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -670,7 +670,15 @@ static errno_t print_vol_info(hr_vol_info_t *info) free(scapa); - printf("| state: %s\n", hr_get_vol_state_str(info->state)); + printf("| state: %s", hr_get_vol_state_str(info->state)); + if (info->state == HR_VOL_REBUILD) { + unsigned int percent = + (info->rebuild_blk * 100) / info->data_blkno; + printf(" (%u%% done)\n", percent); + } else { + printf("\n"); + } + printf("| extents:\n"); for (i = 0; i < info->extent_no; i++) { diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index aa8e4edae3..d9d661e07b 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -119,6 +119,7 @@ typedef struct hr_vol_info { size_t extent_no; size_t hotspare_no; uint64_t data_blkno; + uint64_t rebuild_blk; uint32_t strip_size; size_t bsize; hr_vol_state_t state; diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 4a0964a125..3f49cecc96 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -519,6 +519,7 @@ static void hr_get_vol_info_srv(ipc_call_t *icall) info.hotspare_no = vol->hotspare_no; info.level = vol->level; info.data_blkno = vol->data_blkno; + info.rebuild_blk = vol->rebuild_blk; info.strip_size = vol->strip_size; info.bsize = vol->bsize; info.state = vol->state; From eabc094caca8261cbc9e882a5f640e39d81be02d Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 9 Jun 2025 23:11:16 +0200 Subject: [PATCH 240/324] hr: add superblock erasure op --- uspace/srv/bd/hr/metadata/native.c | 21 +++++++++++++++++++++ uspace/srv/bd/hr/superblock.h | 1 + 2 files changed, 22 insertions(+) diff --git a/uspace/srv/bd/hr/metadata/native.c b/uspace/srv/bd/hr/metadata/native.c index 1814c2b186..1076a0806f 100644 --- a/uspace/srv/bd/hr/metadata/native.c +++ b/uspace/srv/bd/hr/metadata/native.c @@ -59,6 +59,7 @@ static void meta_native_encode(void *, void *); static errno_t meta_native_decode(const void *, void *); static errno_t meta_native_get_block(service_id_t, void **); static errno_t meta_native_write_block(service_id_t, const void *); +static errno_t meta_native_erase_block(service_id_t); static bool meta_native_has_valid_magic(const void *); static bool meta_native_compare_uuids(const void *, const void *); static void meta_native_inc_counter(void *); @@ -79,6 +80,7 @@ hr_superblock_ops_t metadata_native_ops = { .decode = meta_native_decode, .get_block = meta_native_get_block, .write_block = meta_native_write_block, + .erase_block = meta_native_erase_block, .has_valid_magic = meta_native_has_valid_magic, .compare_uuids = meta_native_compare_uuids, .inc_counter = meta_native_inc_counter, @@ -321,6 +323,25 @@ static errno_t meta_native_write_block(service_id_t dev, const void *block) return rc; } +static errno_t meta_native_erase_block(service_id_t dev) +{ + HR_DEBUG("%s()", __func__); + + errno_t rc; + size_t bsize; + + rc = block_get_bsize(dev, &bsize); + if (rc != EOK) + return rc; + + void *zero_block = calloc(1, bsize); + if (zero_block == NULL) + return ENOMEM; + + rc = meta_native_write_block(dev, zero_block); + return rc; +} + static bool meta_native_has_valid_magic(const void *md_v) { HR_DEBUG("%s()", __func__); diff --git a/uspace/srv/bd/hr/superblock.h b/uspace/srv/bd/hr/superblock.h index e006806926..37c7c6fc5c 100644 --- a/uspace/srv/bd/hr/superblock.h +++ b/uspace/srv/bd/hr/superblock.h @@ -50,6 +50,7 @@ typedef struct hr_superblock_ops { errno_t (*decode)(const void *, void *); errno_t (*get_block)(service_id_t, void **); errno_t (*write_block)(service_id_t, const void *); + errno_t (*erase_block)(service_id_t); bool (*has_valid_magic)(const void *); bool (*compare_uuids)(const void *, const void *); void (*inc_counter)(void *); From 0fce1a6cea5ef49159e8731241be6a24121d8cc6 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 9 Jun 2025 23:24:57 +0200 Subject: [PATCH 241/324] hr: rename HR_RLQ_* to HR_LAYOUT_* --- uspace/app/hrctl/hrctl.c | 2 +- uspace/lib/device/include/hr.h | 12 ++++---- uspace/lib/device/src/hr.c | 12 ++++---- .../bd/hr/metadata/foreign/geom/hr_g_mirror.c | 2 +- .../bd/hr/metadata/foreign/geom/hr_g_stripe.c | 2 +- .../metadata/foreign/softraid/hr_softraid.c | 4 +-- uspace/srv/bd/hr/raid5.c | 30 +++++++++---------- 7 files changed, 32 insertions(+), 32 deletions(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index d33b8fe431..49eac43219 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -637,7 +637,7 @@ static errno_t print_vol_info(hr_vol_info_t *info) printf("| metadata type: %s\n", hr_get_metadata_type_str(info->meta_type)); printf("| level: %s\n", hr_get_level_str(info->level)); - if (info->layout != HR_RLQ_NONE) + if (info->layout != HR_LAYOUT_NONE) printf("| layout: %s\n", hr_get_layout_str(info->layout)); diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index d9d661e07b..825e3812d7 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -55,12 +55,12 @@ typedef enum hr_level { } hr_level_t; typedef enum hr_layout { - HR_RLQ_NONE = 0, - HR_RLQ_RAID4_0, /* RAID-4 Non-Rotating Parity 0 */ - HR_RLQ_RAID4_N, /* RAID-4 Non-Rotating Parity N */ - HR_RLQ_RAID5_0R, /* RAID-5 Rotating Parity 0 with Data Restart */ - HR_RLQ_RAID5_NR, /* RAID-5 Rotating Parity N with Data Restart */ - HR_RLQ_RAID5_NC /* RAID-5 Rotating Parity N with Data Continuation */ + HR_LAYOUT_NONE = 0, + HR_LAYOUT_RAID4_0, /* RAID-4 Non-Rotating Parity 0 */ + HR_LAYOUT_RAID4_N, /* RAID-4 Non-Rotating Parity N */ + HR_LAYOUT_RAID5_0R, /* RAID-5 Rotating Parity 0 with Data Restart */ + HR_LAYOUT_RAID5_NR, /* RAID-5 Rotating Parity N with Data Restart */ + HR_LAYOUT_RAID5_NC /* RAID-5 Rotating Parity N with Data Continuation */ } hr_layout_t; typedef enum hr_vol_state { diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index fe8b6c5ed2..0c9fd9b2f6 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -495,17 +495,17 @@ const char *hr_get_ext_state_str(hr_ext_state_t state) const char *hr_get_layout_str(hr_layout_t layout) { switch (layout) { - case HR_RLQ_NONE: + case HR_LAYOUT_NONE: return "RAID layout not set"; - case HR_RLQ_RAID4_0: + case HR_LAYOUT_RAID4_0: return "RAID-4 Non-Rotating Parity 0"; - case HR_RLQ_RAID4_N: + case HR_LAYOUT_RAID4_N: return "RAID-4 Non-Rotating Parity N"; - case HR_RLQ_RAID5_0R: + case HR_LAYOUT_RAID5_0R: return "RAID-5 Rotating Parity 0 with Data Restart"; - case HR_RLQ_RAID5_NR: + case HR_LAYOUT_RAID5_NR: return "RAID-5 Rotating Parity N with Data Restart"; - case HR_RLQ_RAID5_NC: + case HR_LAYOUT_RAID5_NC: return "RAID-5 Rotating Parity N with Data Continuation"; default: return "Invalid RAID layout"; diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c index 5dff4237a5..fd98ea210f 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c @@ -141,7 +141,7 @@ static errno_t meta_gmirror_init_meta2vol(const list_t *list, hr_volume_t *vol) vol->extent_no = main_meta->md_all; - vol->layout = HR_RLQ_NONE; + vol->layout = HR_LAYOUT_NONE; vol->strip_size = 0; diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c index 65990d5979..cb450aaeb6 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c @@ -152,7 +152,7 @@ static errno_t meta_gstripe_init_meta2vol(const list_t *list, hr_volume_t *vol) vol->strip_size = main_meta->md_stripesize; - vol->layout = HR_RLQ_NONE; + vol->layout = HR_LAYOUT_NONE; memcpy(vol->in_mem_md, main_meta, sizeof(struct g_stripe_metadata)); diff --git a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c index c41a1cf1ff..6d8b95bec8 100644 --- a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c +++ b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c @@ -145,9 +145,9 @@ static errno_t meta_softraid_init_meta2vol(const list_t *list, hr_volume_t *vol) vol->extent_no = main_meta->ssdi.ssd_chunk_no; if (main_meta->ssdi.ssd_level == 5) - vol->layout = HR_RLQ_RAID5_NR; + vol->layout = HR_LAYOUT_RAID5_NR; else - vol->layout = HR_RLQ_NONE; + vol->layout = HR_LAYOUT_NONE; vol->strip_size = main_meta->ssdi.ssd_strip_size; diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index e9b9fe353f..4ba98379ae 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -141,7 +141,7 @@ errno_t hr_raid5_init(hr_volume_t *vol) vol->strip_size = HR_STRIP_SIZE; - vol->layout = HR_RLQ_RAID5_NR; + vol->layout = HR_LAYOUT_RAID5_NR; return EOK; } @@ -558,14 +558,14 @@ static errno_t hr_raid5_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, /* parity extent */ uint64_t p_extent; - if (level == HR_LVL_4 && layout == HR_RLQ_RAID4_0) { + if (level == HR_LVL_4 && layout == HR_LAYOUT_RAID4_0) { p_extent = 0; - } else if (level == HR_LVL_4 && layout == HR_RLQ_RAID4_N) { + } else if (level == HR_LVL_4 && layout == HR_LAYOUT_RAID4_N) { p_extent = vol->extent_no - 1; - } else if (level == HR_LVL_5 && layout == HR_RLQ_RAID5_0R) { + } else if (level == HR_LVL_5 && layout == HR_LAYOUT_RAID5_0R) { p_extent = (stripe / (vol->extent_no - 1)) % vol->extent_no; } else if (level == HR_LVL_5 && - (layout == HR_RLQ_RAID5_NR || layout == HR_RLQ_RAID5_NC)) { + (layout == HR_LAYOUT_RAID5_NR || layout == HR_LAYOUT_RAID5_NC)) { p_extent = (vol->extent_no - 1) - (stripe / (vol->extent_no - 1)) % vol->extent_no; } else { @@ -573,17 +573,17 @@ static errno_t hr_raid5_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, } uint64_t extent; - if (level == HR_LVL_4 && layout == HR_RLQ_RAID4_0) { + if (level == HR_LVL_4 && layout == HR_LAYOUT_RAID4_0) { extent = (stripe % (vol->extent_no - 1)) + 1; - } else if (level == HR_LVL_4 && layout == HR_RLQ_RAID4_N) { + } else if (level == HR_LVL_4 && layout == HR_LAYOUT_RAID4_N) { extent = stripe % (vol->extent_no - 1); } else if (level == HR_LVL_5 && - (layout == HR_RLQ_RAID5_0R || layout == HR_RLQ_RAID5_NR)) { + (layout == HR_LAYOUT_RAID5_0R || layout == HR_LAYOUT_RAID5_NR)) { if ((stripe % (vol->extent_no - 1)) < p_extent) extent = stripe % (vol->extent_no - 1); else extent = (stripe % (vol->extent_no - 1)) + 1; - } else if (level == HR_LVL_5 && layout == HR_RLQ_RAID5_NC) { + } else if (level == HR_LVL_5 && layout == HR_LAYOUT_RAID5_NC) { extent = ((stripe % (vol->extent_no - 1)) + p_extent + 1) % vol->extent_no; @@ -674,26 +674,26 @@ static errno_t hr_raid5_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, ext_stripe = stripe / (vol->extent_no - 1); /* stripe level */ - if (level == HR_LVL_5 && layout == HR_RLQ_RAID5_0R) { + if (level == HR_LVL_5 && layout == HR_LAYOUT_RAID5_0R) { p_extent = (stripe / (vol->extent_no - 1)) % vol->extent_no; } else if (level == HR_LVL_5 && - (layout == HR_RLQ_RAID5_NR || layout == HR_RLQ_RAID5_NC)) { + (layout == HR_LAYOUT_RAID5_NR || layout == HR_LAYOUT_RAID5_NC)) { p_extent = (vol->extent_no - 1) - (stripe / (vol->extent_no - 1)) % vol->extent_no; } - if (level == HR_LVL_4 && layout == HR_RLQ_RAID4_0) { + if (level == HR_LVL_4 && layout == HR_LAYOUT_RAID4_0) { extent = (stripe % (vol->extent_no - 1)) + 1; - } else if (level == HR_LVL_4 && layout == HR_RLQ_RAID4_N) { + } else if (level == HR_LVL_4 && layout == HR_LAYOUT_RAID4_N) { extent = stripe % (vol->extent_no - 1); } else if (level == HR_LVL_5 && - (layout == HR_RLQ_RAID5_0R || layout == HR_RLQ_RAID5_NR)) { + (layout == HR_LAYOUT_RAID5_0R || layout == HR_LAYOUT_RAID5_NR)) { if ((stripe % (vol->extent_no - 1)) < p_extent) extent = stripe % (vol->extent_no - 1); else extent = (stripe % (vol->extent_no - 1)) + 1; - } else if (level == HR_LVL_5 && layout == HR_RLQ_RAID5_NC) { + } else if (level == HR_LVL_5 && layout == HR_LAYOUT_RAID5_NC) { extent = ((stripe % (vol->extent_no - 1)) + p_extent + 1) % vol->extent_no; From 9ee9c60b06ad90eda6c61e4ccb3c8909249290c5 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 9 Jun 2025 23:28:55 +0200 Subject: [PATCH 242/324] hr: raid5.c: use RAID 4 layout with RAID 4 level --- uspace/srv/bd/hr/raid5.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 4ba98379ae..6499bfdd1a 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -141,7 +141,10 @@ errno_t hr_raid5_init(hr_volume_t *vol) vol->strip_size = HR_STRIP_SIZE; - vol->layout = HR_LAYOUT_RAID5_NR; + if (vol->level == HR_LVL_4) + vol->layout = HR_LAYOUT_RAID4_N; + else + vol->layout = HR_LAYOUT_RAID5_NR; return EOK; } From b5c95da560221be803f7b14da80c306b21f6c74f Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 10 Jun 2025 00:40:41 +0200 Subject: [PATCH 243/324] hr: raid*_{create,init}(): replace asserts with EINVAL --- uspace/srv/bd/hr/raid0.c | 6 ++++-- uspace/srv/bd/hr/raid1.c | 6 ++++-- uspace/srv/bd/hr/raid5.c | 6 ++++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index b6cf484770..2e2d1236c6 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -82,7 +82,8 @@ errno_t hr_raid0_create(hr_volume_t *new_volume) { HR_DEBUG("%s()", __func__); - assert(new_volume->level == HR_LVL_0); + if (new_volume->level != HR_LVL_0) + return EINVAL; if (new_volume->extent_no < 2) { HR_ERROR("RAID 0 volume needs at least 2 devices\n"); @@ -110,7 +111,8 @@ errno_t hr_raid0_init(hr_volume_t *vol) { HR_DEBUG("%s()", __func__); - assert(vol->level == HR_LVL_0); + if (vol->level != HR_LVL_0) + return EINVAL; uint64_t total_blkno = vol->truncated_blkno * vol->extent_no; diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index abee80b98c..4a7bd84c17 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -92,7 +92,8 @@ errno_t hr_raid1_create(hr_volume_t *new_volume) { HR_DEBUG("%s()", __func__); - assert(new_volume->level == HR_LVL_1); + if (new_volume->level != HR_LVL_1) + return EINVAL; if (new_volume->extent_no < 2) { HR_ERROR("RAID 1 volume needs at least 2 devices\n"); @@ -126,7 +127,8 @@ errno_t hr_raid1_init(hr_volume_t *vol) { HR_DEBUG("%s()", __func__); - assert(vol->level == HR_LVL_1); + if (vol->level != HR_LVL_1) + return EINVAL; vol->data_offset = vol->meta_ops->get_data_offset(); vol->data_blkno = vol->truncated_blkno - vol->meta_ops->get_size(); diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 6499bfdd1a..926ab68c0d 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -95,7 +95,8 @@ errno_t hr_raid5_create(hr_volume_t *new_volume) { HR_DEBUG("%s()", __func__); - assert(new_volume->level == HR_LVL_5 || new_volume->level == HR_LVL_4); + if (new_volume->level != HR_LVL_5 && new_volume->level != HR_LVL_4) + return EINVAL; if (new_volume->extent_no < 3) { HR_ERROR("RAID 5 volume needs at least 3 devices\n"); @@ -128,7 +129,8 @@ errno_t hr_raid5_init(hr_volume_t *vol) { HR_DEBUG("%s()", __func__); - assert(vol->level == HR_LVL_5 || vol->level == HR_LVL_4); + if (vol->level != HR_LVL_5 && vol->level != HR_LVL_4) + return EINVAL; uint64_t total_blkno = vol->truncated_blkno * vol->extent_no; From 177f6ffa5bb0082df268d29d6fc3b6acd3a82f3c Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 10 Jun 2025 00:41:33 +0200 Subject: [PATCH 244/324] hr: stop all volumes: ignore != EOK --- uspace/srv/bd/hr/hr.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 3f49cecc96..a075a00773 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -320,11 +320,8 @@ static void hr_stop_all_srv(ipc_call_t *icall) if (rc != EOK) goto fail; - for (i = 0; i < vol_cnt; i++) { - rc = hr_remove_volume(vol_svcs[i]); - if (rc != EOK) - break; - } + for (i = 0; i < vol_cnt; i++) + (void)hr_remove_volume(vol_svcs[i]); fail: if (vol_svcs != NULL) From 83ff12f71d33c0dbac5d5f7f690e5a534f993e85 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 10 Jun 2025 00:41:51 +0200 Subject: [PATCH 245/324] hr: raid0.c: no need to increment md_counter --- uspace/srv/bd/hr/raid0.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index 2e2d1236c6..5e51d0d766 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -133,9 +133,6 @@ void hr_raid0_vol_state_eval(hr_volume_t *vol) fibril_mutex_lock(&vol->md_lock); - vol->meta_ops->inc_counter(vol->in_mem_md); - /* TODO: save right away */ - fibril_mutex_unlock(&vol->md_lock); fibril_rwlock_read_lock(&vol->states_lock); @@ -154,6 +151,7 @@ void hr_raid0_vol_state_eval(hr_volume_t *vol) return; } } + fibril_rwlock_read_unlock(&vol->states_lock); if (old_state != HR_VOL_ONLINE) { From 7fba1460fce4fbe7ba78460f6556cfc3bd08f204 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 10 Jun 2025 01:41:50 +0200 Subject: [PATCH 246/324] hr: RAID 1: inc meta counter on first write --- .../bd/hr/metadata/foreign/geom/hr_g_mirror.c | 10 ++- .../bd/hr/metadata/foreign/geom/hr_g_stripe.c | 6 +- .../metadata/foreign/softraid/hr_softraid.c | 10 ++- uspace/srv/bd/hr/metadata/native.c | 12 ++- uspace/srv/bd/hr/raid1.c | 80 ++++++++++--------- uspace/srv/bd/hr/superblock.c | 4 +- uspace/srv/bd/hr/superblock.h | 2 +- uspace/srv/bd/hr/util.c | 34 +------- uspace/srv/bd/hr/var.h | 6 ++ 9 files changed, 79 insertions(+), 85 deletions(-) diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c index fd98ea210f..b07cd067f6 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c @@ -61,7 +61,7 @@ static errno_t meta_gmirror_get_block(service_id_t, void **); static errno_t meta_gmirror_write_block(service_id_t, const void *); static bool meta_gmirror_has_valid_magic(const void *); static bool meta_gmirror_compare_uuids(const void *, const void *); -static void meta_gmirror_inc_counter(void *); +static void meta_gmirror_inc_counter(hr_volume_t *); static errno_t meta_gmirror_save(hr_volume_t *, bool); static const char *meta_gmirror_get_devname(const void *); static hr_level_t meta_gmirror_get_level(const void *); @@ -283,12 +283,16 @@ static bool meta_gmirror_compare_uuids(const void *m1_v, const void *m2_v) return false; } -static void meta_gmirror_inc_counter(void *md_v) +static void meta_gmirror_inc_counter(hr_volume_t *vol) { - struct g_mirror_metadata *md = md_v; + fibril_mutex_lock(&vol->md_lock); + + struct g_mirror_metadata *md = vol->in_mem_md; /* XXX: probably md_genid and not md_syncid is incremented */ md->md_genid++; + + fibril_mutex_unlock(&vol->md_lock); } static errno_t meta_gmirror_save(hr_volume_t *vol, bool with_state_callback) diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c index cb450aaeb6..31d111564e 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c @@ -61,7 +61,7 @@ static errno_t meta_gstripe_get_block(service_id_t, void **); static errno_t meta_gstripe_write_block(service_id_t, const void *); static bool meta_gstripe_has_valid_magic(const void *); static bool meta_gstripe_compare_uuids(const void *, const void *); -static void meta_gstripe_inc_counter(void *); +static void meta_gstripe_inc_counter(hr_volume_t *); static errno_t meta_gstripe_save(hr_volume_t *, bool); static const char *meta_gstripe_get_devname(const void *); static hr_level_t meta_gstripe_get_level(const void *); @@ -285,9 +285,9 @@ static bool meta_gstripe_compare_uuids(const void *md1_v, const void *md2_v) return false; } -static void meta_gstripe_inc_counter(void *md_v) +static void meta_gstripe_inc_counter(hr_volume_t *vol) { - (void)md_v; + (void)vol; } static errno_t meta_gstripe_save(hr_volume_t *vol, bool with_state_callback) diff --git a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c index 6d8b95bec8..8a361d657f 100644 --- a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c +++ b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c @@ -61,7 +61,7 @@ static errno_t meta_softraid_get_block(service_id_t, void **); static errno_t meta_softraid_write_block(service_id_t, const void *); static bool meta_softraid_has_valid_magic(const void *); static bool meta_softraid_compare_uuids(const void *, const void *); -static void meta_softraid_inc_counter(void *); +static void meta_softraid_inc_counter(hr_volume_t *); static errno_t meta_softraid_save(hr_volume_t *, bool); static const char *meta_softraid_get_devname(const void *); static hr_level_t meta_softraid_get_level(const void *); @@ -418,11 +418,15 @@ static bool meta_softraid_compare_uuids(const void *m1_v, const void *m2_v) return false; } -static void meta_softraid_inc_counter(void *md_v) +static void meta_softraid_inc_counter(hr_volume_t *vol) { - struct sr_metadata *md = md_v; + fibril_mutex_lock(&vol->md_lock); + + struct sr_metadata *md = vol->in_mem_md; md->ssd_ondisk++; + + fibril_mutex_unlock(&vol->md_lock); } static errno_t meta_softraid_save(hr_volume_t *vol, bool with_state_callback) diff --git a/uspace/srv/bd/hr/metadata/native.c b/uspace/srv/bd/hr/metadata/native.c index 1076a0806f..1078a52db2 100644 --- a/uspace/srv/bd/hr/metadata/native.c +++ b/uspace/srv/bd/hr/metadata/native.c @@ -62,7 +62,7 @@ static errno_t meta_native_write_block(service_id_t, const void *); static errno_t meta_native_erase_block(service_id_t); static bool meta_native_has_valid_magic(const void *); static bool meta_native_compare_uuids(const void *, const void *); -static void meta_native_inc_counter(void *); +static void meta_native_inc_counter(hr_volume_t *); static errno_t meta_native_save(hr_volume_t *, bool); static const char *meta_native_get_devname(const void *); static hr_level_t meta_native_get_level(const void *); @@ -364,11 +364,15 @@ static bool meta_native_compare_uuids(const void *m1p, const void *m2p) return false; } -static void meta_native_inc_counter(void *md_v) +static void meta_native_inc_counter(hr_volume_t *vol) { - hr_metadata_t *md = md_v; + fibril_mutex_lock(&vol->md_lock); + + hr_metadata_t *md = vol->in_mem_md; md->counter++; + + fibril_mutex_unlock(&vol->md_lock); } /* @@ -408,7 +412,7 @@ static errno_t meta_native_save(hr_volume_t *vol, bool with_state_callback) md->index = i; meta_native_encode(md, md_block); rc = meta_native_write_block(ext->svc_id, md_block); - if (with_state_callback && rc != EOK) + if (rc != EOK && with_state_callback) vol->hr_ops.ext_state_cb(vol, i, rc); } diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 4a7bd84c17..7ad5a0aea4 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -55,6 +55,7 @@ #include "util.h" #include "var.h" +static void hr_raid1_vol_state_eval_forced(hr_volume_t *); static size_t hr_raid1_count_good_extents(hr_volume_t *, uint64_t, size_t, uint64_t); static errno_t hr_raid1_bd_op(hr_bd_op_type_t, bd_srv_t *, aoff64_t, size_t, @@ -104,9 +105,7 @@ errno_t hr_raid1_create(hr_volume_t *new_volume) new_volume->hr_bds.ops = &hr_raid1_bd_ops; new_volume->hr_bds.sarg = new_volume; - /* force volume state update */ - hr_mark_vol_state_dirty(new_volume); - hr_raid1_vol_state_eval(new_volume); + hr_raid1_vol_state_eval_forced(new_volume); fibril_rwlock_read_lock(&new_volume->states_lock); hr_vol_state_t state = new_volume->state; @@ -154,16 +153,46 @@ void hr_raid1_vol_state_eval(hr_volume_t *vol) bool exp = true; - /* TODO: could also wrap this */ if (!atomic_compare_exchange_strong(&vol->state_dirty, &exp, false)) return; - fibril_mutex_lock(&vol->md_lock); + vol->meta_ops->inc_counter(vol); + (void)vol->meta_ops->save(vol, WITH_STATE_CALLBACK); - vol->meta_ops->inc_counter(vol->in_mem_md); - /* XXX: save right away */ + hr_raid1_vol_state_eval_forced(vol); +} + +void hr_raid1_ext_state_cb(hr_volume_t *vol, size_t extent, + errno_t rc) +{ + HR_DEBUG("%s()", __func__); + + if (rc == EOK) + return; + + assert(fibril_rwlock_is_locked(&vol->extents_lock)); + + fibril_rwlock_write_lock(&vol->states_lock); - fibril_mutex_unlock(&vol->md_lock); + switch (rc) { + case ENOMEM: + hr_update_ext_state(vol, extent, HR_EXT_INVALID); + break; + case ENOENT: + hr_update_ext_state(vol, extent, HR_EXT_MISSING); + break; + default: + hr_update_ext_state(vol, extent, HR_EXT_FAILED); + } + + hr_mark_vol_state_dirty(vol); + + fibril_rwlock_write_unlock(&vol->states_lock); +} + +static void hr_raid1_vol_state_eval_forced(hr_volume_t *vol) +{ + HR_DEBUG("%s()", __func__); fibril_rwlock_read_lock(&vol->extents_lock); fibril_rwlock_read_lock(&vol->states_lock); @@ -208,34 +237,6 @@ void hr_raid1_vol_state_eval(hr_volume_t *vol) } } -void hr_raid1_ext_state_cb(hr_volume_t *vol, size_t extent, - errno_t rc) -{ - HR_DEBUG("%s()", __func__); - - if (rc == EOK) - return; - - assert(fibril_rwlock_is_locked(&vol->extents_lock)); - - fibril_rwlock_write_lock(&vol->states_lock); - - switch (rc) { - case ENOMEM: - hr_update_ext_state(vol, extent, HR_EXT_INVALID); - break; - case ENOENT: - hr_update_ext_state(vol, extent, HR_EXT_MISSING); - break; - default: - hr_update_ext_state(vol, extent, HR_EXT_FAILED); - } - - hr_mark_vol_state_dirty(vol); - - fibril_rwlock_write_unlock(&vol->states_lock); -} - static errno_t hr_raid1_bd_open(bd_srvs_t *bds, bd_srv_t *bd) { HR_DEBUG("%s()", __func__); @@ -328,6 +329,11 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, if (vol_state == HR_VOL_FAULTY || vol_state == HR_VOL_NONE) return EIO; + if (!vol->data_dirty && type == HR_BD_WRITE) { + vol->meta_ops->inc_counter(vol); + vol->data_dirty = true; + } + if (type == HR_BD_READ || type == HR_BD_WRITE) if (size < cnt * vol->bsize) return EINVAL; @@ -542,7 +548,7 @@ static errno_t hr_raid1_rebuild(void *arg) fibril_rwlock_write_unlock(&vol->states_lock); - rc = vol->meta_ops->save(vol, WITH_STATE_CALLBACK); + (void)vol->meta_ops->save(vol, WITH_STATE_CALLBACK); end: if (rc != EOK) { diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index 454774c36a..4b1a7c4aa6 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -49,12 +49,12 @@ #include "util.h" #include "var.h" +#include "metadata/native.h" + #include "metadata/foreign/geom/g_mirror.h" #include "metadata/foreign/geom/g_stripe.h" #include "metadata/foreign/softraid/softraidvar.h" -#include "metadata/native.h" - extern hr_superblock_ops_t metadata_native_ops; extern hr_superblock_ops_t metadata_gmirror_ops; extern hr_superblock_ops_t metadata_gstripe_ops; diff --git a/uspace/srv/bd/hr/superblock.h b/uspace/srv/bd/hr/superblock.h index 37c7c6fc5c..7c70399594 100644 --- a/uspace/srv/bd/hr/superblock.h +++ b/uspace/srv/bd/hr/superblock.h @@ -53,7 +53,7 @@ typedef struct hr_superblock_ops { errno_t (*erase_block)(service_id_t); bool (*has_valid_magic)(const void *); bool (*compare_uuids)(const void *, const void *); - void (*inc_counter)(void *); + void (*inc_counter)(hr_volume_t *); errno_t (*save)(hr_volume_t *, bool); const char *(*get_devname)(const void *); hr_level_t (*get_level)(const void *); diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index be737b5023..1a2879f7b0 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -150,8 +150,9 @@ errno_t hr_create_vol_struct(hr_volume_t **rvol, hr_level_t level, list_initialize(&vol->range_lock_list); fibril_mutex_initialize(&vol->range_lock_list_lock); - atomic_init(&vol->rebuild_blk, 0); atomic_init(&vol->state_dirty, false); + atomic_init(&vol->data_dirty, false); + atomic_init(&vol->rebuild_blk, 0); atomic_init(&vol->open_cnt, 0); *rvol = vol; @@ -856,45 +857,14 @@ static errno_t hr_util_assemble_from_matching_list(list_t *list, meta_ops->init_meta2vol(list, vol); - /* - * TODO: something like mark md dirty or whatever - * - probably will be handled by each md type differently, - * by specific function pointers - * - deal with this when foreign md will be handled - * - * XXX: if thats the only thing that can change in metadata - * during volume runtime, then whatever, but if more - * things will need to be synced, think of something more clever - * - * TODO: remove from here and increment it the "first" time (if nothing - * happens - no state changes, no rebuild, etc) - only after the first - * write... but for now leave it here - */ - (void)vol->meta_ops->inc_counter(vol->in_mem_md); - rc = vol->hr_ops.create(vol); if (rc != EOK) goto error; - /* - * XXX: register it here - * ... if it fails on EEXIST try different name... like + 1 on the end - * - * or have metadata edit utility as a part of hrctl..., or create - * the original name + 4 random characters, tell the user that the device - * was created with this new name, and add a option to hrctl to rename - * an active array, and then write the new dirty metadata... - * - * or just refuse to assemble a name that is already used... - * - * TODO: discuss - */ rc = hr_register_volume(vol); if (rc != EOK) goto error; - (void)vol->meta_ops->save(vol, WITH_STATE_CALLBACK); - fibril_rwlock_write_lock(&hr_volumes_lock); list_append(&vol->lvolumes, &hr_volumes); fibril_rwlock_write_unlock(&hr_volumes_lock); diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index f61cac6ed9..5539882881 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -100,6 +100,12 @@ typedef struct hr_volume { _Atomic bool state_dirty; /* dirty state */ + /* + * used to increment metadata counter on first write, + * allowing non-destructive read-only access + */ + _Atomic bool data_dirty; + /* XXX: atomic_uint_least64_t? */ _Atomic uint64_t rebuild_blk; /* rebuild position */ _Atomic int open_cnt; /* open/close() counter */ From 6791fbf39cb12c73df14fedede20159dd4f42073 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 10 Jun 2025 01:46:00 +0200 Subject: [PATCH 247/324] hr: foreign metadata: un-silent save() --- uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c | 6 ++---- uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c | 2 +- uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c | 3 +-- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c index b07cd067f6..1eb3c8019f 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c @@ -305,12 +305,10 @@ static errno_t meta_gmirror_save(hr_volume_t *vol, bool with_state_callback) /* * cannot support right now, because would need to store the * metadata for all disks, because of hardcoded provider names and - * most importantly, disk unique ids + * more importantly, disk unique ids */ - /* silent */ - return EOK; - /* return ENOTSUP; */ + return ENOTSUP; } static const char *meta_gmirror_get_devname(const void *md_v) diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c index 31d111564e..6f2fc8f0ea 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c @@ -294,7 +294,7 @@ static errno_t meta_gstripe_save(hr_volume_t *vol, bool with_state_callback) { HR_DEBUG("%s()", __func__); - return EOK; + return ENOTSUP; } static const char *meta_gstripe_get_devname(const void *md_v) diff --git a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c index 8a361d657f..da9bd0f6b0 100644 --- a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c +++ b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c @@ -433,8 +433,7 @@ static errno_t meta_softraid_save(hr_volume_t *vol, bool with_state_callback) { HR_DEBUG("%s()", __func__); - /* silent */ - return EOK; + return ENOTSUP; } static const char *meta_softraid_get_devname(const void *md_v) From 13ada526b7e33d1825b72e049bc6fdae493201bc Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 10 Jun 2025 02:30:43 +0200 Subject: [PATCH 248/324] hr: make failing an extent erase the superblock --- uspace/srv/bd/hr/hr.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index a075a00773..4a42c45bf4 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -341,11 +341,11 @@ static void hr_fail_extent_srv(ipc_call_t *icall) HR_DEBUG("%s()", __func__); service_id_t svc_id; - size_t fail_extent; + size_t extent_idx_to_fail; hr_volume_t *vol; svc_id = (service_id_t)ipc_get_arg1(icall); - fail_extent = (size_t)ipc_get_arg2(icall); + extent_idx_to_fail = (size_t)ipc_get_arg2(icall); vol = hr_get_volume(svc_id); if (vol == NULL) { @@ -353,10 +353,12 @@ static void hr_fail_extent_srv(ipc_call_t *icall) return; } + hr_extent_t *ext = &vol->extents[extent_idx_to_fail]; + fibril_rwlock_read_lock(&vol->extents_lock); fibril_rwlock_write_lock(&vol->states_lock); - switch (vol->extents[fail_extent].state) { + switch (ext->state) { case HR_EXT_NONE: case HR_EXT_MISSING: case HR_EXT_FAILED: @@ -365,7 +367,8 @@ static void hr_fail_extent_srv(ipc_call_t *icall) async_answer_0(icall, EINVAL); return; default: - hr_update_ext_state(vol, fail_extent, HR_EXT_FAILED); + hr_update_ext_state(vol, extent_idx_to_fail, HR_EXT_FAILED); + (void)vol->meta_ops->erase_block(ext->svc_id); hr_mark_vol_state_dirty(vol); } From e0622a6d55bb82ba2dad9fdd676ff9468861c206 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 10 Jun 2025 03:23:06 +0200 Subject: [PATCH 249/324] hr: raid1.c: increment meta counter on first write --- uspace/srv/bd/hr/raid1.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 7ad5a0aea4..57f7d4f58b 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -152,7 +152,6 @@ void hr_raid1_vol_state_eval(hr_volume_t *vol) HR_DEBUG("%s()", __func__); bool exp = true; - if (!atomic_compare_exchange_strong(&vol->state_dirty, &exp, false)) return; @@ -329,9 +328,12 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, if (vol_state == HR_VOL_FAULTY || vol_state == HR_VOL_NONE) return EIO; - if (!vol->data_dirty && type == HR_BD_WRITE) { + /* increment metadata counter only on first write */ + bool exp = false; + if (type == HR_BD_WRITE && + atomic_compare_exchange_strong(&vol->data_dirty, &exp, true)) { vol->meta_ops->inc_counter(vol); - vol->data_dirty = true; + vol->meta_ops->save(vol, WITH_STATE_CALLBACK); } if (type == HR_BD_READ || type == HR_BD_WRITE) @@ -496,6 +498,13 @@ static errno_t hr_raid1_rebuild(void *arg) */ fibril_rwlock_read_lock(&vol->extents_lock); + /* increment metadata counter only on first write */ + bool exp = false; + if (atomic_compare_exchange_strong(&vol->data_dirty, &exp, true)) { + vol->meta_ops->inc_counter(vol); + vol->meta_ops->save(vol, WITH_STATE_CALLBACK); + } + hr_range_lock_t *rl = NULL; unsigned int percent, old_percent = 100; From a62079d832da4d9a32352ac39c84e42c43dd1a0e Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Wed, 11 Jun 2025 21:53:28 +0200 Subject: [PATCH 250/324] hr: move struct hr_range_lock to util.h --- uspace/srv/bd/hr/util.h | 29 ++++++++++++++++++++--------- uspace/srv/bd/hr/var.h | 11 ----------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index 668f5759df..ebdc5134c2 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -44,15 +44,6 @@ #include "superblock.h" #include "var.h" -struct dev_list_member { - link_t link; - service_id_t svc_id; - void *md; - bool inited; - bool md_present; - bool fini; -}; - #define HR_DEBUG(format, ...) \ log_msg(LOG_DEFAULT, LVL_DEBUG, format, ##__VA_ARGS__) @@ -65,6 +56,26 @@ struct dev_list_member { #define HR_ERROR(format, ...) \ log_msg(LOG_DEFAULT, LVL_ERROR, format, ##__VA_ARGS__) +struct dev_list_member { + link_t link; + service_id_t svc_id; + void *md; + bool inited; + bool md_present; + bool fini; +}; + +typedef struct hr_range_lock { + link_t link; + fibril_mutex_t lock; + hr_volume_t *vol; /* back-pointer to volume */ + uint64_t off; /* start of the range */ + uint64_t len; /* length of the range */ + + size_t pending; /* prot. by vol->range_lock_list_lock */ + bool ignore; /* prot. by vol->range_lock_list_lock */ +} hr_range_lock_t; + extern errno_t hr_create_vol_struct(hr_volume_t **, hr_level_t, const char *, hr_metadata_type_t); extern void hr_destroy_vol_struct(hr_volume_t *); diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index 5539882881..46ce7895f4 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -122,17 +122,6 @@ typedef enum { #define WITH_STATE_CALLBACK true #define NO_STATE_CALLBACK false -typedef struct hr_range_lock { - link_t link; - fibril_mutex_t lock; - hr_volume_t *vol; /* back-pointer to volume */ - uint64_t off; /* start of the range */ - uint64_t len; /* length of the range */ - - size_t pending; /* prot. by vol->range_lock_list_lock */ - bool ignore; /* prot. by vol->range_lock_list_lock */ -} hr_range_lock_t; - extern errno_t hr_raid0_create(hr_volume_t *); extern errno_t hr_raid1_create(hr_volume_t *); extern errno_t hr_raid5_create(hr_volume_t *); From 234212a2cb8e6d38d313b28851c69c84ff5486bd Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 17 Jun 2025 15:22:46 +0200 Subject: [PATCH 251/324] hr: rename data_dirty to first_write --- uspace/srv/bd/hr/raid1.c | 29 +++++++++++++++-------------- uspace/srv/bd/hr/util.c | 9 +++++++-- uspace/srv/bd/hr/util.h | 3 ++- uspace/srv/bd/hr/var.h | 3 +-- 4 files changed, 25 insertions(+), 19 deletions(-) diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 57f7d4f58b..709884c2ca 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -161,16 +161,15 @@ void hr_raid1_vol_state_eval(hr_volume_t *vol) hr_raid1_vol_state_eval_forced(vol); } -void hr_raid1_ext_state_cb(hr_volume_t *vol, size_t extent, - errno_t rc) +void hr_raid1_ext_state_cb(hr_volume_t *vol, size_t extent, errno_t rc) { HR_DEBUG("%s()", __func__); + assert(fibril_rwlock_is_locked(&vol->extents_lock)); + if (rc == EOK) return; - assert(fibril_rwlock_is_locked(&vol->extents_lock)); - fibril_rwlock_write_lock(&vol->states_lock); switch (rc) { @@ -218,7 +217,10 @@ static void hr_raid1_vol_state_eval_forced(hr_volume_t *vol) if (old_state != HR_VOL_REBUILD) { /* XXX: allow REBUILD on INVALID extents */ - if (vol->hotspare_no > 0) { + fibril_mutex_lock(&vol->hotspare_lock); + size_t hs_no = vol->hotspare_no; + fibril_mutex_unlock(&vol->hotspare_lock); + if (hs_no > 0) { fid_t fib = fibril_create(hr_raid1_rebuild, vol); if (fib == 0) @@ -321,6 +323,9 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, size_t i; uint64_t rebuild_blk; + if (size < cnt * vol->bsize) + return EINVAL; + fibril_rwlock_read_lock(&vol->states_lock); hr_vol_state_t vol_state = vol->state; fibril_rwlock_read_unlock(&vol->states_lock); @@ -331,22 +336,18 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, /* increment metadata counter only on first write */ bool exp = false; if (type == HR_BD_WRITE && - atomic_compare_exchange_strong(&vol->data_dirty, &exp, true)) { + atomic_compare_exchange_strong(&vol->first_write, &exp, true)) { vol->meta_ops->inc_counter(vol); vol->meta_ops->save(vol, WITH_STATE_CALLBACK); } - if (type == HR_BD_READ || type == HR_BD_WRITE) - if (size < cnt * vol->bsize) - return EINVAL; - rc = hr_check_ba_range(vol, cnt, ba); if (rc != EOK) return rc; /* allow full dev sync */ - if (type != HR_BD_SYNC || ba != 0) - hr_add_ba_offset(vol, &ba); + if (!(type == HR_BD_SYNC && ba == 0 && cnt == 0)) + hr_add_data_offset(vol, &ba); /* * extent order has to be locked for the whole IO duration, @@ -490,7 +491,7 @@ static errno_t hr_raid1_rebuild(void *arg) size_t cnt; uint64_t ba = 0; - hr_add_ba_offset(vol, &ba); + hr_add_data_offset(vol, &ba); /* * XXX: this is useless here after simplified DI, because @@ -500,7 +501,7 @@ static errno_t hr_raid1_rebuild(void *arg) /* increment metadata counter only on first write */ bool exp = false; - if (atomic_compare_exchange_strong(&vol->data_dirty, &exp, true)) { + if (atomic_compare_exchange_strong(&vol->first_write, &exp, true)) { vol->meta_ops->inc_counter(vol); vol->meta_ops->save(vol, WITH_STATE_CALLBACK); } diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 1a2879f7b0..03d24f9462 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -151,7 +151,7 @@ errno_t hr_create_vol_struct(hr_volume_t **rvol, hr_level_t level, fibril_mutex_initialize(&vol->range_lock_list_lock); atomic_init(&vol->state_dirty, false); - atomic_init(&vol->data_dirty, false); + atomic_init(&vol->first_write, false); atomic_init(&vol->rebuild_blk, 0); atomic_init(&vol->open_cnt, 0); @@ -396,11 +396,16 @@ errno_t hr_check_ba_range(hr_volume_t *vol, size_t cnt, uint64_t ba) return EOK; } -void hr_add_ba_offset(hr_volume_t *vol, uint64_t *ba) +void hr_add_data_offset(hr_volume_t *vol, uint64_t *ba) { *ba = *ba + vol->data_offset; } +void hr_sub_data_offset(hr_volume_t *vol, uint64_t *ba) +{ + *ba = *ba - vol->data_offset; +} + void hr_update_ext_state(hr_volume_t *vol, size_t ext_idx, hr_ext_state_t s) { if (vol->level != HR_LVL_0) diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index ebdc5134c2..fa9324e64e 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -86,7 +86,8 @@ extern errno_t hr_init_extents_from_cfg(hr_volume_t *, hr_config_t *); extern void hr_fini_devs(hr_volume_t *); extern errno_t hr_register_volume(hr_volume_t *); extern errno_t hr_check_ba_range(hr_volume_t *, size_t, uint64_t); -extern void hr_add_ba_offset(hr_volume_t *, uint64_t *); +extern void hr_add_data_offset(hr_volume_t *, uint64_t *); +extern void hr_sub_data_offset(hr_volume_t *, uint64_t *); extern void hr_update_ext_state(hr_volume_t *, size_t, hr_ext_state_t); extern void hr_update_hotspare_state(hr_volume_t *, size_t, hr_ext_state_t); extern void hr_update_vol_state(hr_volume_t *, hr_vol_state_t); diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index 46ce7895f4..f5bbc6c9bd 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -104,9 +104,8 @@ typedef struct hr_volume { * used to increment metadata counter on first write, * allowing non-destructive read-only access */ - _Atomic bool data_dirty; + _Atomic bool first_write; - /* XXX: atomic_uint_least64_t? */ _Atomic uint64_t rebuild_blk; /* rebuild position */ _Atomic int open_cnt; /* open/close() counter */ hr_vol_state_t state; /* volume state */ From f0950d25ca930150730465e65799981bceeddc0b Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 17 Jun 2025 15:23:57 +0200 Subject: [PATCH 252/324] hr: add malloc_waitok() and calloc_waitok() --- uspace/srv/bd/hr/util.c | 24 ++++++++++++++++++++++++ uspace/srv/bd/hr/util.h | 6 ++++++ 2 files changed, 30 insertions(+) diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 03d24f9462..51d45e8d3a 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -75,6 +75,30 @@ extern loc_srv_t *hr_srv; extern list_t hr_volumes; extern fibril_rwlock_t hr_volumes_lock; +/* + * malloc() wrapper that behaves like + * FreeBSD malloc(9) with M_WAITOK flag. + * + * Return value is never NULL. + */ +void *malloc_waitok(size_t size) +{ + void *ret; + while ((ret = malloc(size)) == NULL) + fibril_usleep(MSEC2USEC(250)); /* sleep 250ms */ + + return ret; +} + +void *calloc_waitok(size_t nmemb, size_t size) +{ + void *ret; + while ((ret = calloc(nmemb, size)) == NULL) + fibril_usleep(MSEC2USEC(250)); /* sleep 250ms */ + + return ret; +} + errno_t hr_create_vol_struct(hr_volume_t **rvol, hr_level_t level, const char *devname, hr_metadata_type_t metadata_type) { diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index fa9324e64e..9426706983 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -76,6 +76,12 @@ typedef struct hr_range_lock { bool ignore; /* prot. by vol->range_lock_list_lock */ } hr_range_lock_t; +extern void *malloc_waitok(size_t) + __attribute__((malloc)); + +extern void *calloc_waitok(size_t, size_t) + __attribute__((malloc)); + extern errno_t hr_create_vol_struct(hr_volume_t **, hr_level_t, const char *, hr_metadata_type_t); extern void hr_destroy_vol_struct(hr_volume_t *); From d574c11b6115bba8c33ea620b9adf56e2049b4d0 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 17 Jun 2025 15:27:48 +0200 Subject: [PATCH 253/324] hr: fge: use malloc_waitok() --- uspace/srv/bd/hr/fge.c | 37 ++++++++----------------------------- 1 file changed, 8 insertions(+), 29 deletions(-) diff --git a/uspace/srv/bd/hr/fge.c b/uspace/srv/bd/hr/fge.c index 4f02a5d0d7..e96ded67c6 100644 --- a/uspace/srv/bd/hr/fge.c +++ b/uspace/srv/bd/hr/fge.c @@ -51,6 +51,7 @@ #include #include "fge.h" +#include "util.h" static void *hr_fpool_make_storage(hr_fpool_t *, ssize_t *); static void hr_fpool_group_epilogue(hr_fpool_t *); @@ -63,7 +64,6 @@ static ssize_t hr_fpool_get_free_slot(hr_fpool_t *); hr_fpool_t *hr_fpool_create(size_t fibril_cnt, size_t max_wus, size_t wu_storage_size) { - /* TODO: allow wu_storage_size to be 0 (we want to save mem) */ assert(max_wus > 0 && wu_storage_size > 0); void *bitmap_data = NULL; @@ -101,6 +101,7 @@ hr_fpool_t *hr_fpool_create(size_t fibril_cnt, size_t max_wus, for (size_t i = 0; i < fibril_cnt; i++) { result->fibrils[i] = fibril_create(fge_fibril, result); fibril_start(result->fibrils[i]); + /* fibril_detach(result->fibrils[i]); */ } return result; @@ -138,16 +139,7 @@ hr_fgroup_t *hr_fgroup_create(hr_fpool_t *parent, size_t wu_cnt) { assert(wu_cnt > 0); - /* - * XXX: we can also get rid of this malloc() call, - * somewhat... - * - * Have some fgroups also pre-allocated for maximum - * pre-allocation power :-) - */ - hr_fgroup_t *result = malloc(sizeof(hr_fgroup_t)); - if (result == NULL) - return NULL; + hr_fgroup_t *result = malloc_waitok(sizeof(hr_fgroup_t)); result->reserved_cnt = 0; result->own_mem = NULL; @@ -168,18 +160,14 @@ hr_fgroup_t *hr_fgroup_create(hr_fpool_t *parent, size_t wu_cnt) * the fallback storage. */ size_t taking = parent->wu_storage_free_count; - result->own_mem = malloc(parent->wu_size * (wu_cnt - taking)); - if (result->own_mem == NULL) - goto bad; + result->own_mem = malloc_waitok(parent->wu_size * (wu_cnt - taking)); result->reserved_cnt = taking; parent->wu_storage_free_count = 0; } if (result->reserved_cnt > 0) { result->memslots = - malloc(sizeof(size_t) * result->reserved_cnt); - if (result->memslots == NULL) - goto bad; + malloc_waitok(sizeof(size_t) * result->reserved_cnt); } fibril_mutex_unlock(&parent->lock); @@ -197,18 +185,6 @@ hr_fgroup_t *hr_fgroup_create(hr_fpool_t *parent, size_t wu_cnt) fibril_condvar_initialize(&result->all_done); return result; - -bad: - parent->wu_storage_free_count += result->reserved_cnt; - fibril_mutex_unlock(&parent->lock); - - if (result->memslots != NULL) - free(result->memslots); - if (result->own_mem != NULL) - free(result->own_mem); - free(result); - - return NULL; } void *hr_fgroup_alloc(hr_fgroup_t *group) @@ -217,6 +193,8 @@ void *hr_fgroup_alloc(hr_fgroup_t *group) fibril_mutex_lock(&group->lock); + assert(group->submitted < group->wu_cnt); + if (group->reserved_avail > 0) { ssize_t memslot; storage = hr_fpool_make_storage(group->pool, &memslot); @@ -224,6 +202,7 @@ void *hr_fgroup_alloc(hr_fgroup_t *group) group->reserved_avail--; group->memslots[group->submitted] = memslot; } else { + assert(group->own_mem != NULL); storage = group->own_mem + group->pool->wu_size * group->own_used; group->own_used++; From 66ef60bc4494ba732b169fcdac81ea9be05014ad Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 17 Jun 2025 15:28:50 +0200 Subject: [PATCH 254/324] hr: range locks: add noalloc lock acquire --- uspace/srv/bd/hr/util.c | 17 +++++++++++++++++ uspace/srv/bd/hr/util.h | 4 +++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 51d45e8d3a..3a74311956 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -54,6 +54,8 @@ #include "util.h" #include "var.h" +static hr_range_lock_t *hr_range_lock_acquire_internal(hr_range_lock_t *, + hr_volume_t *, uint64_t, uint64_t); static bool hr_range_lock_overlap(hr_range_lock_t *, hr_range_lock_t *); static errno_t hr_add_svc_linked_to_list(list_t *, service_id_t, bool, void *); static void free_dev_list_member(struct dev_list_member *); @@ -537,6 +539,13 @@ size_t hr_count_extents(hr_volume_t *vol, hr_ext_state_t state) return count; } +void hr_range_lock_acquire_noalloc(hr_range_lock_t *rl, hr_volume_t *vol, + uint64_t ba, uint64_t cnt) +{ + assert(rl != NULL); + (void)hr_range_lock_acquire_internal(rl, vol, ba, cnt); +} + hr_range_lock_t *hr_range_lock_acquire(hr_volume_t *vol, uint64_t ba, uint64_t cnt) { @@ -544,6 +553,14 @@ hr_range_lock_t *hr_range_lock_acquire(hr_volume_t *vol, uint64_t ba, if (rl == NULL) return NULL; + return hr_range_lock_acquire_internal(rl, vol, ba, cnt); +} + +static hr_range_lock_t *hr_range_lock_acquire_internal(hr_range_lock_t *rl, + hr_volume_t *vol, uint64_t ba, uint64_t cnt) +{ + printf("hr_range_lock_acquire_internal got: 0x%p\n", rl); + rl->vol = vol; rl->off = ba; rl->len = cnt; diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index 9426706983..8163de1958 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -102,9 +102,11 @@ extern void hr_update_hotspare_svc_id(hr_volume_t *, size_t, service_id_t); extern void hr_sync_all_extents(hr_volume_t *); extern size_t hr_count_extents(hr_volume_t *, hr_ext_state_t); extern void hr_mark_vol_state_dirty(hr_volume_t *); -extern void hr_range_lock_release(hr_range_lock_t *); +extern void hr_range_lock_acquire_noalloc(hr_range_lock_t *, hr_volume_t *, + uint64_t, uint64_t); extern hr_range_lock_t *hr_range_lock_acquire(hr_volume_t *, uint64_t, uint64_t); +extern void hr_range_lock_release(hr_range_lock_t *); extern errno_t hr_util_try_assemble(hr_config_t *, size_t *); extern errno_t hr_util_add_hotspare(hr_volume_t *, service_id_t); From 73425d4f4b6b0c8284f65bd8a58b8439af654d21 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 17 Jun 2025 15:29:56 +0200 Subject: [PATCH 255/324] hr: rai0.c: use renamed hr_add_data_offset() --- uspace/srv/bd/hr/raid0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index 5e51d0d766..183bdc01b0 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -314,7 +314,7 @@ static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, phys_block = stripe * strip_size + strip_off; cnt = min(left, strip_size - strip_off); len = vol->bsize * cnt; - hr_add_ba_offset(vol, &phys_block); + hr_add_data_offset(vol, &phys_block); hr_io_t *io = hr_fgroup_alloc(group); io->extent = extent; From b22ea202107f450b2d752b06f3f2c48c9baff729 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 17 Jun 2025 15:32:31 +0200 Subject: [PATCH 256/324] hr: rai1.c: make rebuild_blk evaluation more conservative --- uspace/srv/bd/hr/raid1.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 709884c2ca..09c7443893 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -303,7 +303,7 @@ static size_t hr_raid1_count_good_extents(hr_volume_t *vol, uint64_t ba, for (size_t i = 0; i < vol->extent_no; i++) { if (vol->extents[i].state == HR_EXT_ONLINE || (vol->extents[i].state == HR_EXT_REBUILD && - ba < rebuild_blk)) { + rebuild_blk >= ba)) { count++; } } @@ -419,7 +419,7 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, for (i = 0; i < vol->extent_no; i++) { if (vol->extents[i].state != HR_EXT_ONLINE && (vol->extents[i].state != HR_EXT_REBUILD || - ba >= rebuild_blk)) { + ba > rebuild_blk)) { /* * When the extent is being rebuilt, * we only write to the part that is already From 9d1685b9d20320c0d757562d21216a101ea960c6 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 17 Jun 2025 16:14:09 +0200 Subject: [PATCH 257/324] hr: ENOMEM safe wrappers for block_direct_* ops --- uspace/srv/bd/hr/fge.c | 4 ++-- uspace/srv/bd/hr/io.c | 41 +++++++++++++++++++++++++++++++++++++++++ uspace/srv/bd/hr/io.h | 4 ++++ 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/uspace/srv/bd/hr/fge.c b/uspace/srv/bd/hr/fge.c index e96ded67c6..33886620f7 100644 --- a/uspace/srv/bd/hr/fge.c +++ b/uspace/srv/bd/hr/fge.c @@ -326,8 +326,8 @@ static errno_t fge_fibril(void *arg) } else { fibril_mutex_lock(&group->lock); group->finished_fail++; - if (rc == ENOMEM) - group->final_errno = ENOMEM; + if (rc == EAGAIN) + group->final_errno = EAGAIN; fibril_mutex_unlock(&group->lock); } diff --git a/uspace/srv/bd/hr/io.c b/uspace/srv/bd/hr/io.c index afb079aaa7..19daee67ad 100644 --- a/uspace/srv/bd/hr/io.c +++ b/uspace/srv/bd/hr/io.c @@ -46,6 +46,47 @@ static errno_t exec_io_op(hr_io_t *); +/** 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; diff --git a/uspace/srv/bd/hr/io.h b/uspace/srv/bd/hr/io.h index 48076b5643..90c48fbfe5 100644 --- a/uspace/srv/bd/hr/io.h +++ b/uspace/srv/bd/hr/io.h @@ -51,6 +51,10 @@ typedef struct hr_io { errno_t hr_io_worker(void *); errno_t hr_io_worker_basic(void *); +extern errno_t hr_write_direct(service_id_t, uint64_t, size_t, const void *); +extern errno_t hr_read_direct(service_id_t, uint64_t, size_t, void *); +extern errno_t hr_sync_cache(service_id_t, uint64_t, size_t); + #endif /** @} From a3486f22ef90cb49886854387bb881de5188d3c7 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 17 Jun 2025 16:17:20 +0200 Subject: [PATCH 258/324] hr: parallel RAID 5 --- uspace/srv/bd/hr/io.c | 209 ++++++- uspace/srv/bd/hr/io.h | 33 +- uspace/srv/bd/hr/meson.build | 1 + uspace/srv/bd/hr/parity_stripe.c | 926 ++++++++++++++++++++++++++++++ uspace/srv/bd/hr/parity_stripe.h | 118 ++++ uspace/srv/bd/hr/raid5.c | 941 ++++++++++++++++--------------- uspace/srv/bd/hr/util.c | 46 +- uspace/srv/bd/hr/util.h | 1 + uspace/srv/bd/hr/var.h | 3 +- 9 files changed, 1776 insertions(+), 502 deletions(-) create mode 100644 uspace/srv/bd/hr/parity_stripe.c create mode 100644 uspace/srv/bd/hr/parity_stripe.h diff --git a/uspace/srv/bd/hr/io.c b/uspace/srv/bd/hr/io.c index 19daee67ad..93cb5594a2 100644 --- a/uspace/srv/bd/hr/io.c +++ b/uspace/srv/bd/hr/io.c @@ -38,9 +38,12 @@ #include #include #include +#include +#include #include #include "io.h" +#include "parity_stripe.h" #include "util.h" #include "var.h" @@ -114,6 +117,210 @@ errno_t hr_io_worker_basic(void *arg) 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 = 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 = malloc_waitok(io->cnt * io->vol->bsize); + + rc = hr_write_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, stripe->p_extent, rc); + + return rc; +} + static errno_t exec_io_op(hr_io_t *io) { size_t ext_idx = io->extent; @@ -153,7 +360,7 @@ static errno_t exec_io_op(hr_io_t *io) io->cnt, io->data_write); break; default: - return EINVAL; + assert(0); } HR_DEBUG("WORKER (%p) rc: %s\n", io, str_error(rc)); diff --git a/uspace/srv/bd/hr/io.h b/uspace/srv/bd/hr/io.h index 90c48fbfe5..a16a88df8c 100644 --- a/uspace/srv/bd/hr/io.h +++ b/uspace/srv/bd/hr/io.h @@ -36,25 +36,48 @@ #ifndef _HR_IO_H #define _HR_IO_H +#include "parity_stripe.h" #include "var.h" +#include "util.h" typedef struct hr_io { - hr_bd_op_type_t type; + hr_bd_op_type_t type; /* read/write/sync */ uint64_t ba; uint64_t cnt; - size_t extent; void *data_read; const void *data_write; - hr_volume_t *vol; + size_t extent; /* extent index */ + hr_volume_t *vol; /* volume back-pointer */ } hr_io_t; -errno_t hr_io_worker(void *); -errno_t hr_io_worker_basic(void *); +typedef struct hr_io_raid5 { + uint64_t ba; + uint64_t cnt; + void *data_read; + const void *data_write; + size_t extent; + uint64_t strip_off; /* needed for offseting parity commits */ + hr_stripe_t *stripe; + hr_volume_t *vol; +} hr_io_raid5_t; extern errno_t hr_write_direct(service_id_t, uint64_t, size_t, const void *); extern errno_t hr_read_direct(service_id_t, uint64_t, size_t, void *); extern errno_t hr_sync_cache(service_id_t, uint64_t, size_t); +extern errno_t hr_io_worker(void *); +extern errno_t hr_io_worker_basic(void *); + +extern errno_t hr_io_raid5_basic_reader(void *); +extern errno_t hr_io_raid5_reader(void *); +extern errno_t hr_io_raid5_basic_writer(void *); +extern errno_t hr_io_raid5_writer(void *); +extern errno_t hr_io_raid5_noop_writer(void *); +extern errno_t hr_io_raid5_parity_getter(void *); +extern errno_t hr_io_raid5_subtract_writer(void *); +extern errno_t hr_io_raid5_reconstruct_reader(void *); +extern errno_t hr_io_raid5_parity_writer(void *); + #endif /** @} diff --git a/uspace/srv/bd/hr/meson.build b/uspace/srv/bd/hr/meson.build index c96a77d9e6..85ee18f68f 100644 --- a/uspace/srv/bd/hr/meson.build +++ b/uspace/srv/bd/hr/meson.build @@ -36,6 +36,7 @@ src = files( 'metadata/foreign/softraid/hr_softraid.c', 'metadata/foreign/softraid/softraid.c', 'metadata/native.c', + 'parity_stripe.c', 'raid0.c', 'raid1.c', 'raid5.c', diff --git a/uspace/srv/bd/hr/parity_stripe.c b/uspace/srv/bd/hr/parity_stripe.c new file mode 100644 index 0000000000..38ea5e8221 --- /dev/null +++ b/uspace/srv/bd/hr/parity_stripe.c @@ -0,0 +1,926 @@ +/* + * 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 "io.h" +#include "parity_stripe.h" +#include "util.h" +#include "var.h" + +static void execute_stripe_degraded_mixed(hr_stripe_t *, size_t); +static void execute_stripe_degraded(hr_stripe_t *, size_t); +static void execute_stripe_optimal_reconstruct(hr_stripe_t *); +static void execute_stripe_optimal_subtract(hr_stripe_t *); +static void execute_write_stripe(hr_stripe_t *, size_t); +static void execute_read_stripe(hr_stripe_t *, size_t); +static void execute_stripe_degraded_good(hr_stripe_t *, size_t); +static bool hr_stripe_range_non_extension(const range_t *, const range_t *, + range_t *); +static size_t hr_stripe_merge_extent_spans(hr_stripe_t *, size_t, range_t [2]); +static void hr_reset_stripe(hr_stripe_t *); +static void hr_stripe_extend_range(range_t *, const range_t *); +static bool hr_ranges_overlap(const range_t *, const range_t *, range_t *); + +hr_stripe_t *hr_create_stripes(hr_volume_t *vol, size_t cnt, bool write) +{ + hr_stripe_t *stripes = calloc(cnt, sizeof(*stripes)); + if (stripes == NULL) + return NULL; + + for (size_t i = 0; i < cnt; i++) { + fibril_mutex_initialize(&stripes[i].parity_lock); + fibril_condvar_initialize(&stripes[i].ps_added_cv); + stripes[i].vol = vol; + stripes[i].write = write; + stripes[i].parity = calloc(1, vol->strip_size); + if (stripes[i].parity == NULL) + goto error; + stripes[i].extent_span = + calloc(vol->extent_no, sizeof(*stripes[i].extent_span)); + if (stripes[i].extent_span == NULL) + goto error; + } + + return stripes; +error: + hr_destroy_stripes(stripes, cnt); + return NULL; +} + +void hr_destroy_stripes(hr_stripe_t *stripes, size_t cnt) +{ + if (stripes == NULL) + return; + + for (size_t i = 0; i < cnt; i++) { + if (stripes[i].parity != NULL) + free(stripes[i].parity); + if (stripes[i].extent_span != NULL) + free(stripes[i].extent_span); + } + + free(stripes); +} + +void hr_stripe_commit_parity(hr_stripe_t *stripe, uint64_t strip_off, + const void *data, uint64_t size) +{ + fibril_mutex_lock(&stripe->parity_lock); + hr_raid5_xor(stripe->parity + strip_off, data, size); + stripe->ps_added++; + fibril_condvar_broadcast(&stripe->ps_added_cv); + fibril_mutex_unlock(&stripe->parity_lock); +} + +void hr_stripe_wait_for_parity_commits(hr_stripe_t *stripe) +{ + fibril_mutex_lock(&stripe->parity_lock); + while ((!stripe->p_count_final || + stripe->ps_added < stripe->ps_to_be_added) && !stripe->abort) { + fibril_condvar_wait(&stripe->ps_added_cv, &stripe->parity_lock); + } + fibril_mutex_unlock(&stripe->parity_lock); +} + +void hr_stripe_parity_abort(hr_stripe_t *stripe) +{ + fibril_mutex_lock(&stripe->parity_lock); + stripe->abort = true; + fibril_condvar_broadcast(&stripe->ps_added_cv); + fibril_mutex_unlock(&stripe->parity_lock); +} + +void execute_stripe(hr_stripe_t *stripe, size_t bad_extent) +{ + if (stripe->write) + execute_write_stripe(stripe, bad_extent); + else + execute_read_stripe(stripe, bad_extent); +} + +void wait_for_stripe(hr_stripe_t *stripe) +{ + stripe->rc = hr_fgroup_wait(stripe->worker_group, NULL, NULL); + if (stripe->rc == EAGAIN) + hr_reset_stripe(stripe); + else + stripe->done = true; +} + +static void execute_stripe_degraded_good(hr_stripe_t *stripe, size_t bad_extent) +{ + hr_volume_t *vol = stripe->vol; + + stripe->ps_to_be_added = stripe->strips_touched; /* writers */ + stripe->ps_to_be_added += stripe->range_count; /* parity readers */ + stripe->p_count_final = true; + + size_t worker_cnt = stripe->strips_touched + stripe->range_count * 2; + stripe->worker_group = hr_fgroup_create(vol->fge, worker_cnt); + + for (size_t e = 0; e < vol->extent_no; e++) { + if (e == bad_extent || e == stripe->p_extent) + continue; + if (stripe->extent_span[e].cnt == 0) + continue; + + hr_io_raid5_t *io = hr_fgroup_alloc(stripe->worker_group); + io->extent = e; + io->data_write = stripe->extent_span[e].data_write; + io->ba = stripe->extent_span[e].range.start; + io->cnt = stripe->extent_span[e].cnt; + io->strip_off = stripe->extent_span[e].strip_off * vol->bsize; + io->vol = vol; + io->stripe = stripe; + + hr_fgroup_submit(stripe->worker_group, + hr_io_raid5_subtract_writer, io); + } + + for (size_t r = 0; r < stripe->range_count; r++) { + hr_io_raid5_t *p_reader = hr_fgroup_alloc(stripe->worker_group); + p_reader->extent = stripe->p_extent; + p_reader->ba = stripe->total_height[r].start; + p_reader->cnt = stripe->total_height[r].end - + stripe->total_height[r].start + 1; + p_reader->vol = vol; + p_reader->stripe = stripe; + + p_reader->strip_off = p_reader->ba; + hr_sub_data_offset(vol, &p_reader->strip_off); + p_reader->strip_off %= vol->strip_size / vol->bsize; + p_reader->strip_off *= vol->bsize; + + hr_fgroup_submit(stripe->worker_group, + hr_io_raid5_reconstruct_reader, p_reader); + + hr_io_raid5_t *p_writer = hr_fgroup_alloc(stripe->worker_group); + p_writer->extent = stripe->p_extent; + p_writer->ba = stripe->total_height[r].start; + p_writer->cnt = stripe->total_height[r].end - + stripe->total_height[r].start + 1; + p_writer->vol = vol; + p_writer->stripe = stripe; + + p_writer->strip_off = p_writer->ba; + hr_sub_data_offset(vol, &p_writer->strip_off); + p_writer->strip_off %= vol->strip_size / vol->bsize; + p_writer->strip_off *= vol->bsize; + + hr_fgroup_submit(stripe->worker_group, + hr_io_raid5_parity_writer, p_writer); + } +} + +static void execute_stripe_degraded_mixed(hr_stripe_t *stripe, size_t bad_extent) +{ + hr_volume_t *vol = stripe->vol; + + size_t worker_cnt = (vol->extent_no - 2) * 3 + 3; /* upper bound */ + stripe->worker_group = hr_fgroup_create(vol->fge, worker_cnt); + + stripe->ps_to_be_added = 1; + + hr_io_raid5_t *nop_write = hr_fgroup_alloc(stripe->worker_group); + nop_write->ba = stripe->extent_span[bad_extent].range.start; + nop_write->cnt = stripe->extent_span[bad_extent].cnt; + nop_write->strip_off = + stripe->extent_span[bad_extent].strip_off * vol->bsize; + nop_write->data_write = stripe->extent_span[bad_extent].data_write; + nop_write->vol = vol; + nop_write->stripe = stripe; + + hr_fgroup_submit(stripe->worker_group, hr_io_raid5_noop_writer, + nop_write); + + for (size_t e = 0; e < vol->extent_no; e++) { + if (e == bad_extent || e == stripe->p_extent) + continue; + + range_t uncommon = { 0, 0 }; + bool has_uncommon; + has_uncommon = hr_stripe_range_non_extension( + &stripe->extent_span[bad_extent].range, + &stripe->extent_span[e].range, + &uncommon); + + if (stripe->extent_span[e].cnt == 0 || has_uncommon) { + stripe->ps_to_be_added++; + + hr_io_raid5_t *io = + hr_fgroup_alloc(stripe->worker_group); + io->extent = e; + if (stripe->extent_span[bad_extent].cnt == 0) { + io->ba = + stripe->extent_span[bad_extent].range.start; + io->cnt = stripe->extent_span[bad_extent].cnt; + } else { + io->ba = uncommon.start; + io->cnt = uncommon.end - uncommon.start + 1; + } + io->strip_off = + stripe->extent_span[bad_extent].strip_off * + vol->bsize; + io->vol = vol; + io->stripe = stripe; + + hr_fgroup_submit(stripe->worker_group, + hr_io_raid5_reconstruct_reader, io); + + if (stripe->extent_span[e].cnt == 0) + continue; + } + + range_t overlap_range; + bool overlap_up = true; + if (hr_ranges_overlap(&stripe->extent_span[e].range, + &stripe->extent_span[bad_extent].range, + &overlap_range)) { + stripe->ps_to_be_added++; + + hr_io_raid5_t *io = + hr_fgroup_alloc(stripe->worker_group); + io->extent = e; + io->ba = overlap_range.start; + io->cnt = overlap_range.end - overlap_range.start + 1; + + size_t diff = overlap_range.start - + stripe->extent_span[e].range.start; + + io->strip_off = + (stripe->extent_span[e].strip_off + diff) * + vol->bsize; + + io->data_write = stripe->extent_span[e].data_write; + io->data_write += diff * vol->bsize; + if (diff == 0) + overlap_up = false; + + io->vol = vol; + io->stripe = stripe; + + hr_fgroup_submit(stripe->worker_group, + hr_io_raid5_writer, io); + } + + bool has_independent; + range_t independent = { 0, 0 }; + has_independent = hr_stripe_range_non_extension( + &stripe->extent_span[e].range, + &stripe->extent_span[bad_extent].range, + &independent); + if (has_independent) { + stripe->ps_to_be_added++; + + hr_io_raid5_t *io = + hr_fgroup_alloc(stripe->worker_group); + io->extent = e; + io->ba = independent.start; + io->cnt = independent.end - independent.start + 1; + size_t diff = 0; + if (!overlap_up) { + diff = overlap_range.end - + overlap_range.start + 1; + } + io->strip_off = + (stripe->extent_span[e].strip_off + diff) * + vol->bsize; + io->data_write = stripe->extent_span[e].data_write; + io->data_write += diff * vol->bsize; + io->vol = vol; + io->stripe = stripe; + + hr_fgroup_submit(stripe->worker_group, + hr_io_raid5_subtract_writer, io); + } + } + + bool has_independent = false; + range_t independent = { 0, 0 }; + for (size_t r = 0; r < stripe->range_count; r++) { + has_independent = hr_stripe_range_non_extension( + &stripe->total_height[r], + &stripe->extent_span[bad_extent].range, + &independent); + if (has_independent) { + stripe->ps_to_be_added++; + + hr_io_raid5_t *io = + hr_fgroup_alloc(stripe->worker_group); + io->extent = stripe->p_extent; + io->ba = independent.start; + io->cnt = independent.end - independent.start + 1; + + io->strip_off = io->ba; + hr_sub_data_offset(vol, &io->strip_off); + io->strip_off %= vol->strip_size / vol->bsize; + io->strip_off *= vol->bsize; + + io->vol = vol; + io->stripe = stripe; + + hr_fgroup_submit(stripe->worker_group, + hr_io_raid5_reconstruct_reader, io); + } + + hr_io_raid5_t *pio = hr_fgroup_alloc(stripe->worker_group); + pio->extent = stripe->p_extent; + pio->ba = stripe->total_height[r].start; + pio->cnt = stripe->total_height[r].end - + stripe->total_height[r].start + 1; + pio->strip_off = pio->ba; + hr_sub_data_offset(vol, &pio->strip_off); + pio->strip_off %= vol->strip_size / vol->bsize; + pio->strip_off *= vol->bsize; + pio->vol = vol; + pio->stripe = stripe; + + hr_fgroup_submit(stripe->worker_group, + hr_io_raid5_parity_writer, pio); + } + + stripe->p_count_final = true; + fibril_condvar_broadcast(&stripe->ps_added_cv); +} + +static void execute_stripe_degraded(hr_stripe_t *stripe, size_t bad_extent) +{ + hr_volume_t *vol = stripe->vol; + + /* parity is bad, issue non-redundant writes */ + if (bad_extent == stripe->p_extent) { + stripe->worker_group = + hr_fgroup_create(vol->fge, stripe->strips_touched); + + for (size_t e = 0; e < vol->extent_no; e++) { + if (e == bad_extent) + continue; + if (stripe->extent_span[e].cnt == 0) + continue; + + hr_io_raid5_t *io = + hr_fgroup_alloc(stripe->worker_group); + io->extent = e; + io->data_write = stripe->extent_span[e].data_write; + io->ba = stripe->extent_span[e].range.start; + io->cnt = stripe->extent_span[e].cnt; + io->strip_off = + stripe->extent_span[e].strip_off * vol->bsize; + io->vol = vol; + io->stripe = stripe; + + hr_fgroup_submit(stripe->worker_group, + hr_io_raid5_basic_writer, io); + } + + return; + } + + stripe->range_count = hr_stripe_merge_extent_spans(stripe, + vol->extent_no, stripe->total_height); + + if (stripe->extent_span[bad_extent].cnt > 0) + execute_stripe_degraded_mixed(stripe, bad_extent); + else + execute_stripe_degraded_good(stripe, bad_extent); +} + +static void execute_stripe_optimal_reconstruct(hr_stripe_t *stripe) +{ + hr_volume_t *vol = stripe->vol; + + stripe->range_count = hr_stripe_merge_extent_spans(stripe, + vol->extent_no, stripe->total_height); + + bool full_stripe = false; + size_t worker_cnt; + if (stripe->strips_touched == vol->extent_no - 1 && + stripe->partial_strips_touched == 0) { + /* full-stripe */ + worker_cnt = stripe->strips_touched; /* writers */ + worker_cnt += 1; /* parity writer */ + + stripe->ps_to_be_added = stripe->strips_touched; + stripe->p_count_final = true; + + full_stripe = true; + } else { + worker_cnt = stripe->strips_touched; /* writers */ + + /* readers (upper bound) */ + worker_cnt += (vol->extent_no - 1) - stripe->strips_touched; + worker_cnt += stripe->partial_strips_touched; + + worker_cnt += stripe->range_count; /* parity writer(s) */ + + stripe->ps_to_be_added = stripe->strips_touched; /* writers */ + } + + stripe->worker_group = hr_fgroup_create(vol->fge, worker_cnt); + + for (size_t e = 0; e < vol->extent_no; e++) { + if (e == stripe->p_extent) + continue; + + if (stripe->extent_span[e].cnt == 0) + continue; + + hr_io_raid5_t *io = hr_fgroup_alloc(stripe->worker_group); + io->extent = e; + io->data_write = stripe->extent_span[e].data_write; + io->ba = stripe->extent_span[e].range.start; + io->cnt = stripe->extent_span[e].cnt; + io->strip_off = stripe->extent_span[e].strip_off * vol->bsize; + io->vol = vol; + io->stripe = stripe; + + hr_fgroup_submit(stripe->worker_group, hr_io_raid5_writer, io); + } + + for (size_t r = 0; r < stripe->range_count; r++) { + if (full_stripe) + goto skip_readers; + for (size_t e = 0; e < vol->extent_no; e++) { + if (e == stripe->p_extent) + continue; + + range_t range_extension = { 0, 0 }; + + bool need_reader = false; + if (stripe->extent_span[e].cnt == 0) { + range_extension = stripe->total_height[r]; + need_reader = true; + } else { + need_reader = hr_stripe_range_non_extension( + &stripe->total_height[r], + &stripe->extent_span[e].range, + &range_extension); + } + + if (need_reader) { + stripe->ps_to_be_added++; + + hr_io_raid5_t *io = + hr_fgroup_alloc(stripe->worker_group); + io->extent = e; + io->ba = range_extension.start; + io->cnt = range_extension.end - + range_extension.start + 1; + io->vol = vol; + io->stripe = stripe; + + io->strip_off = io->ba; + hr_sub_data_offset(vol, &io->strip_off); + io->strip_off %= vol->strip_size / vol->bsize; + io->strip_off *= vol->bsize; + + hr_fgroup_submit(stripe->worker_group, + hr_io_raid5_reconstruct_reader, io); + } + } + + stripe->p_count_final = true; + fibril_condvar_broadcast(&stripe->ps_added_cv); + + skip_readers: + + /* parity writer */ + hr_io_raid5_t *io = hr_fgroup_alloc(stripe->worker_group); + io->extent = stripe->p_extent; + io->ba = stripe->total_height[r].start; + io->cnt = stripe->total_height[r].end - + stripe->total_height[r].start + 1; + io->vol = vol; + io->stripe = stripe; + + io->strip_off = io->ba; + hr_sub_data_offset(vol, &io->strip_off); + io->strip_off %= vol->strip_size / vol->bsize; + io->strip_off *= vol->bsize; + + hr_fgroup_submit(stripe->worker_group, + hr_io_raid5_parity_writer, io); + } +} + +static void execute_stripe_optimal_subtract(hr_stripe_t *stripe) +{ + hr_volume_t *vol = stripe->vol; + + stripe->range_count = hr_stripe_merge_extent_spans(stripe, + vol->extent_no, stripe->total_height); + + size_t worker_cnt; + worker_cnt = stripe->strips_touched; /* writers */ + worker_cnt += stripe->range_count * 2; /* parity readers & writers */ + + stripe->ps_to_be_added = stripe->strips_touched; /* writers */ + stripe->ps_to_be_added += stripe->range_count; /* parity readers */ + stripe->p_count_final = true; + + stripe->worker_group = hr_fgroup_create(vol->fge, worker_cnt); + + for (size_t e = 0; e < vol->extent_no; e++) { + if (e == stripe->p_extent) + continue; + + if (stripe->extent_span[e].cnt == 0) + continue; + + hr_io_raid5_t *io = hr_fgroup_alloc(stripe->worker_group); + io->extent = e; + io->data_write = stripe->extent_span[e].data_write; + io->ba = stripe->extent_span[e].range.start; + io->cnt = stripe->extent_span[e].cnt; + io->strip_off = stripe->extent_span[e].strip_off * vol->bsize; + io->vol = vol; + io->stripe = stripe; + + hr_fgroup_submit(stripe->worker_group, + hr_io_raid5_subtract_writer, io); + } + + for (size_t r = 0; r < stripe->range_count; r++) { + hr_io_raid5_t *p_reader = hr_fgroup_alloc(stripe->worker_group); + p_reader->extent = stripe->p_extent; + p_reader->ba = stripe->total_height[r].start; + p_reader->cnt = stripe->total_height[r].end - + stripe->total_height[r].start + 1; + p_reader->vol = vol; + p_reader->stripe = stripe; + + p_reader->strip_off = p_reader->ba; + hr_sub_data_offset(vol, &p_reader->strip_off); + p_reader->strip_off %= vol->strip_size / vol->bsize; + p_reader->strip_off *= vol->bsize; + + hr_fgroup_submit(stripe->worker_group, + hr_io_raid5_reconstruct_reader, p_reader); + + hr_io_raid5_t *p_writer = hr_fgroup_alloc(stripe->worker_group); + p_writer->extent = stripe->p_extent; + p_writer->ba = stripe->total_height[r].start; + p_writer->cnt = stripe->total_height[r].end - + stripe->total_height[r].start + 1; + p_writer->vol = vol; + p_writer->stripe = stripe; + + p_writer->strip_off = p_writer->ba; + hr_sub_data_offset(vol, &p_writer->strip_off); + p_writer->strip_off %= vol->strip_size / vol->bsize; + p_writer->strip_off *= vol->bsize; + + hr_fgroup_submit(stripe->worker_group, + hr_io_raid5_parity_writer, p_writer); + } + +} + +static void execute_write_stripe(hr_stripe_t *stripe, size_t bad_extent) +{ + hr_volume_t *vol = stripe->vol; + + if (bad_extent < vol->extent_no) { + execute_stripe_degraded(stripe, bad_extent); + return; + } + + if (stripe->subtract) + execute_stripe_optimal_subtract(stripe); + else + execute_stripe_optimal_reconstruct(stripe); +} + +static void execute_read_stripe(hr_stripe_t *stripe, size_t bad_extent) +{ + hr_volume_t *vol = stripe->vol; + + /* no parity involved */ + if (bad_extent == vol->extent_no || + bad_extent == stripe->p_extent || + stripe->extent_span[bad_extent].cnt == 0) { + stripe->worker_group = + hr_fgroup_create(vol->fge, stripe->strips_touched); + for (size_t e = 0; e < vol->extent_no; e++) { + if (e == bad_extent || e == stripe->p_extent) + continue; + if (stripe->extent_span[e].cnt == 0) + continue; + + hr_io_raid5_t *io = + hr_fgroup_alloc(stripe->worker_group); + io->extent = e; + io->data_read = stripe->extent_span[e].data_read; + io->ba = stripe->extent_span[e].range.start; + io->cnt = stripe->extent_span[e].cnt; + io->strip_off = + stripe->extent_span[e].strip_off * vol->bsize; + io->vol = vol; + io->stripe = stripe; + + hr_fgroup_submit(stripe->worker_group, + hr_io_raid5_basic_reader, io); + } + + return; + } + + /* parity involved */ + + size_t worker_cnt = (vol->extent_no - 2) * 2 + 1; /* upper bound */ + stripe->worker_group = hr_fgroup_create(vol->fge, worker_cnt); + + stripe->ps_to_be_added = 0; + + for (size_t e = 0; e < vol->extent_no; e++) { + if (e == bad_extent || e == stripe->p_extent) + continue; + + range_t uncommon = { 0, 0 }; + bool has_uncommon; + has_uncommon = hr_stripe_range_non_extension( + &stripe->extent_span[bad_extent].range, + &stripe->extent_span[e].range, + &uncommon); + + if (stripe->extent_span[e].cnt == 0 || has_uncommon) { + + stripe->ps_to_be_added++; + + hr_io_raid5_t *io = + hr_fgroup_alloc(stripe->worker_group); + io->extent = e; + if (stripe->extent_span[bad_extent].cnt == 0) { + io->ba = + stripe->extent_span[bad_extent].range.start; + io->cnt = stripe->extent_span[bad_extent].cnt; + } else { + io->ba = uncommon.start; + io->cnt = uncommon.end - uncommon.start + 1; + } + io->strip_off = + stripe->extent_span[bad_extent].strip_off * + vol->bsize; + io->vol = vol; + io->stripe = stripe; + + hr_fgroup_submit(stripe->worker_group, + hr_io_raid5_reconstruct_reader, io); + + if (stripe->extent_span[e].cnt == 0) + continue; + } + + range_t overlap_range; + bool overlap_up = true; + if (hr_ranges_overlap(&stripe->extent_span[e].range, + &stripe->extent_span[bad_extent].range, + &overlap_range)) { + + stripe->ps_to_be_added++; + + hr_io_raid5_t *io = + hr_fgroup_alloc(stripe->worker_group); + io->extent = e; + io->ba = overlap_range.start; + io->cnt = overlap_range.end - overlap_range.start + 1; + + size_t diff = overlap_range.start - + stripe->extent_span[e].range.start; + io->strip_off = + (stripe->extent_span[e].strip_off + diff) * + vol->bsize; + + io->data_read = stripe->extent_span[e].data_read; + io->data_read += diff * vol->bsize; + if (diff == 0) + overlap_up = false; + + io->vol = vol; + io->stripe = stripe; + + hr_fgroup_submit(stripe->worker_group, + hr_io_raid5_reader, io); + } + + bool has_independent; + range_t independent = { 0, 0 }; + has_independent = hr_stripe_range_non_extension( + &stripe->extent_span[e].range, + &uncommon, + &independent); + if (has_independent) { + hr_io_raid5_t *io = + hr_fgroup_alloc(stripe->worker_group); + io->extent = e; + io->ba = independent.start; + io->cnt = independent.end - independent.start + 1; + size_t diff = 0; + if (!overlap_up) { + diff = + overlap_range.end - overlap_range.start + 1; + } + io->strip_off = + (stripe->extent_span[e].strip_off + diff) * + vol->bsize; + io->data_read = stripe->extent_span[e].data_read; + io->data_read += diff * vol->bsize; + io->vol = vol; + io->stripe = stripe; + + hr_fgroup_submit(stripe->worker_group, + hr_io_raid5_basic_reader, io); + } + } + + stripe->ps_to_be_added++; + + hr_io_raid5_t *io = hr_fgroup_alloc(stripe->worker_group); + io->extent = stripe->p_extent; + io->ba = stripe->extent_span[bad_extent].range.start; + io->cnt = stripe->extent_span[bad_extent].cnt; + io->strip_off = stripe->extent_span[bad_extent].strip_off * vol->bsize; + io->vol = vol; + io->stripe = stripe; + + hr_fgroup_submit(stripe->worker_group, hr_io_raid5_reconstruct_reader, + io); + + stripe->p_count_final = true; + fibril_condvar_broadcast(&stripe->ps_added_cv); + + hr_io_raid5_t *pcopier_io = hr_fgroup_alloc(stripe->worker_group); + pcopier_io->cnt = stripe->extent_span[bad_extent].cnt; + pcopier_io->strip_off = + stripe->extent_span[bad_extent].strip_off * vol->bsize; + pcopier_io->data_read = stripe->extent_span[bad_extent].data_read; + pcopier_io->vol = vol; + pcopier_io->stripe = stripe; + + hr_fgroup_submit(stripe->worker_group, hr_io_raid5_parity_getter, + pcopier_io); +} + +/** Get non-overlapping part of 2 ranges. + * + * Return part of @param r1 not in @param r2. + * + * @param r1 Main range. + * @param r2 Queried range. + * @param out Place to store resulting range. + * + * @return true if output range is non-empty, else false. + */ +static bool hr_stripe_range_non_extension(const range_t *r1, const range_t *r2, + range_t *out) +{ + if (r1->end < r2->start) { + *out = *r1; + return true; + } + + if (r1->start > r2->end) { + *out = *r1; + return true; + } + + if (r1->start < r2->start && r1->end >= r2->start) { + out->start = r1->start; + out->end = r2->start - 1; + return out->start <= out->end; + } + + if (r1->start <= r2->end && r1->end > r2->end) { + out->start = r2->end + 1; + out->end = r1->end; + return out->start <= out->end; + } + + return false; +} + +/** Merge adjascent or overlapping extent spans. + * + * @param s Stripe. + * @param extent_no Number of extents. + * @param out Place to store resulting ranges. + * + * @return Number of resulting ranges. + */ +static size_t hr_stripe_merge_extent_spans(hr_stripe_t *s, size_t extent_no, + range_t out[2]) +{ + size_t out_count = 0; + + for (size_t i = 0; i < extent_no; i++) { + if (s->extent_span[i].cnt == 0) + continue; + const range_t *r = &s->extent_span[i].range; + bool merged = false; + + for (size_t j = 0; j < out_count; j++) { + if (hr_ranges_overlap(&out[j], r, NULL)) { + hr_stripe_extend_range(&out[j], r); + merged = true; + + if (out_count == 2 && + hr_ranges_overlap(&out[0], &out[1], NULL)) { + hr_stripe_extend_range(&out[0], &out[1]); + out_count = 1; + } + + break; + } + } + + if (!merged) { + assert(out_count < 2); + out[out_count++] = *r; + } + } + + return out_count; +} + +static void hr_reset_stripe(hr_stripe_t *stripe) +{ + printf("%s\n", __func__); + + memset(stripe->parity, 0, stripe->vol->strip_size); + stripe->ps_added = 0; + stripe->ps_to_be_added = 0; + stripe->p_count_final = false; + + stripe->rc = EOK; + stripe->abort = false; + stripe->done = false; +} + +/** Extend a range. + * + * @param r1 Output range. + * @param r2 Range to extend the output one with. + * + */ +static void hr_stripe_extend_range(range_t *r1, const range_t *r2) +{ + if (r2->start < r1->start) + r1->start = r2->start; + if (r2->end > r1->end) + r1->end = r2->end; +} + +static bool hr_ranges_overlap(const range_t *a, const range_t *b, range_t *out) +{ + uint64_t start = a->start > b->start ? a->start : b->start; + uint64_t end = a->end < b->end ? a->end : b->end; + + if (start <= end) { + if (out != NULL) { + out->start = start; + out->end = end; + } + + return true; + } + + return false; +} + +/** @} + */ diff --git a/uspace/srv/bd/hr/parity_stripe.h b/uspace/srv/bd/hr/parity_stripe.h new file mode 100644 index 0000000000..99867aa0c3 --- /dev/null +++ b/uspace/srv/bd/hr/parity_stripe.h @@ -0,0 +1,118 @@ +/* + * 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 + */ + +#ifndef _HR_STRIPE_H +#define _HR_STRIPE_H + +#include +#include +#include +#include + +#include "io.h" +#include "var.h" + +typedef struct { + uint64_t start; + uint64_t end; +} range_t; + +typedef struct hr_stripe { + hr_volume_t *vol; + bool write; + bool subtract; + size_t strips_touched; + size_t partial_strips_touched; + struct { + range_t range; + uint64_t cnt; + uint64_t strip_off; + const void *data_write; + void *data_read; + } *extent_span; + uint64_t p_extent; /* parity extent index for this stripe */ + + hr_fgroup_t *worker_group; + + errno_t rc; + bool abort; + bool done; + + fibril_mutex_t parity_lock; + uint8_t *parity; /* the actual parity strip */ + + /* parity writers waiting until this many parity commits */ + size_t ps_to_be_added; + size_t ps_added; /* number of parities commited to stripe */ + fibril_condvar_t ps_added_cv; + bool p_count_final; + + /* + * Possibly need 2 ranges because single IO that partially spans + * 2 strips and overflows to second one without creating an adjacent + * range results in parity not being continous. + * + * Example: 2+1 extents, 4 block strip, last extent parity + * + * E0 E1 P + * +----+ +----+ +-----+ + * | | | IO | | IOP | + * |----| |----| |-----| + * | | | | | | + * |----| |----| |-----| + * | | | | | | + * |----| |----| |-----| + * | IO | | | | IOP | + * +----+ +----+ +-----+ + * + * - need 2 parity writers + */ + range_t total_height[2]; /* for knowing writing parity range(s) */ + size_t range_count; +} hr_stripe_t; + +extern hr_stripe_t *hr_create_stripes(hr_volume_t *, size_t, bool); +extern void hr_destroy_stripes(hr_stripe_t *, size_t); +extern void hr_stripe_commit_parity(hr_stripe_t *, uint64_t, const void *, + uint64_t); +extern void hr_stripe_wait_for_parity_commits(hr_stripe_t *); +extern void hr_stripe_parity_abort(hr_stripe_t *); +extern void execute_stripe(hr_stripe_t *, size_t); +extern void wait_for_stripe(hr_stripe_t *); + +#endif + +/** @} + */ diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 926ab68c0d..668efd5d5a 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -49,23 +49,19 @@ #include #include +#include "io.h" +#include "parity_stripe.h" #include "superblock.h" #include "util.h" #include "var.h" -static errno_t hr_raid5_vol_usable(hr_volume_t *); -static ssize_t hr_raid5_get_bad_ext(hr_volume_t *); -static errno_t hr_raid5_update_vol_state(hr_volume_t *); -static void xor(void *, const void *, size_t); +static void hr_raid5_vol_state_eval_forced(hr_volume_t *); + +static size_t hr_raid5_parity_extent(hr_level_t, hr_layout_t, size_t, + uint64_t); +static size_t hr_raid5_data_extent(hr_level_t, hr_layout_t, size_t, uint64_t, + uint64_t); -static errno_t hr_raid5_read_degraded(hr_volume_t *, uint64_t, uint64_t, - void *, size_t); -static errno_t hr_raid5_write(hr_volume_t *, uint64_t, uint64_t, aoff64_t, - const void *, size_t); -static errno_t hr_raid5_write_parity(hr_volume_t *, uint64_t, uint64_t, - uint64_t, const void *, size_t); -static errno_t hr_raid5_bd_op(hr_bd_op_type_t, bd_srv_t *, aoff64_t, size_t, - void *, const void *, size_t); static errno_t hr_raid5_rebuild(void *); /* bdops */ @@ -103,21 +99,20 @@ errno_t hr_raid5_create(hr_volume_t *new_volume) return EINVAL; } - fibril_rwlock_write_lock(&new_volume->states_lock); - - errno_t rc = hr_raid5_update_vol_state(new_volume); - if (rc != EOK) { - HR_NOTE("\"%s\": unusable state, not creating\n", - new_volume->devname); - fibril_rwlock_write_unlock(&new_volume->states_lock); - return rc; - } - bd_srvs_init(&new_volume->hr_bds); new_volume->hr_bds.ops = &hr_raid5_bd_ops; new_volume->hr_bds.sarg = new_volume; - fibril_rwlock_write_unlock(&new_volume->states_lock); + hr_raid5_vol_state_eval_forced(new_volume); + + fibril_rwlock_read_lock(&new_volume->states_lock); + hr_vol_state_t state = new_volume->state; + fibril_rwlock_read_unlock(&new_volume->states_lock); + if (state == HR_VOL_FAULTY || state == HR_VOL_NONE) { + HR_NOTE("\"%s\": unusable state, not creating\n", + new_volume->devname); + return EINVAL; + } return EOK; } @@ -132,14 +127,10 @@ errno_t hr_raid5_init(hr_volume_t *vol) if (vol->level != HR_LVL_5 && vol->level != HR_LVL_4) return EINVAL; - uint64_t total_blkno = vol->truncated_blkno * vol->extent_no; - vol->data_offset = vol->meta_ops->get_data_offset(); - vol->data_blkno = total_blkno; - /* count md blocks */ - vol->data_blkno -= vol->meta_ops->get_size() * vol->extent_no; - vol->data_blkno -= vol->truncated_blkno; /* count parity */ + uint64_t single_sz = vol->truncated_blkno - vol->meta_ops->get_size(); + vol->data_blkno = single_sz * (vol->extent_no - 1); vol->strip_size = HR_STRIP_SIZE; @@ -153,52 +144,54 @@ errno_t hr_raid5_init(hr_volume_t *vol) void hr_raid5_vol_state_eval(hr_volume_t *vol) { - fibril_mutex_lock(&vol->lock); - fibril_rwlock_write_lock(&vol->states_lock); - (void)hr_raid5_update_vol_state(vol); - fibril_rwlock_write_unlock(&vol->states_lock); - fibril_mutex_unlock(&vol->lock); + HR_DEBUG("%s()", __func__); + + bool exp = true; + if (!atomic_compare_exchange_strong(&vol->state_dirty, &exp, false)) + return; + + vol->meta_ops->inc_counter(vol); + (void)vol->meta_ops->save(vol, WITH_STATE_CALLBACK); + + hr_raid5_vol_state_eval_forced(vol); } errno_t hr_raid5_add_hotspare(hr_volume_t *vol, service_id_t hotspare) { HR_DEBUG("%s()", __func__); - fibril_mutex_lock(&vol->lock); - errno_t rc = hr_util_add_hotspare(vol, hotspare); - if (rc != EOK) - goto end; - /* - * If the volume is degraded, start rebuild right away. - */ - if (vol->state == HR_VOL_DEGRADED) { - HR_DEBUG("hr_raid5_add_hotspare(): volume in DEGRADED state, " - "spawning new rebuild fibril\n"); - fid_t fib = fibril_create(hr_raid5_rebuild, vol); - if (fib == 0) { - fibril_mutex_unlock(&vol->hotspare_lock); - fibril_mutex_unlock(&vol->lock); - return ENOMEM; - } - fibril_start(fib); - fibril_detach(fib); - } - -end: - fibril_mutex_unlock(&vol->lock); + hr_raid5_vol_state_eval(vol); return rc; } -void hr_raid5_ext_state_cb(hr_volume_t *vol, size_t extent, - errno_t rc) +void hr_raid5_ext_state_cb(hr_volume_t *vol, size_t extent, errno_t rc) { - if (rc == ENOENT) + HR_DEBUG("%s()", __func__); + + assert(fibril_rwlock_is_locked(&vol->extents_lock)); + + if (rc == EOK) + return; + + fibril_rwlock_write_lock(&vol->states_lock); + + switch (rc) { + case ENOMEM: + hr_update_ext_state(vol, extent, HR_EXT_INVALID); + break; + case ENOENT: hr_update_ext_state(vol, extent, HR_EXT_MISSING); - else if (rc != EOK) + break; + default: hr_update_ext_state(vol, extent, HR_EXT_FAILED); + } + + hr_mark_vol_state_dirty(vol); + + fibril_rwlock_write_unlock(&vol->states_lock); } static errno_t hr_raid5_bd_open(bd_srvs_t *bds, bd_srv_t *bd) @@ -225,491 +218,515 @@ static errno_t hr_raid5_bd_close(bd_srv_t *bd) static errno_t hr_raid5_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) { - return hr_raid5_bd_op(HR_BD_SYNC, bd, ba, cnt, NULL, NULL, 0); -} - -static errno_t hr_raid5_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, - void *buf, size_t size) -{ - return hr_raid5_bd_op(HR_BD_READ, bd, ba, cnt, buf, NULL, size); -} - -static errno_t hr_raid5_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, - const void *data, size_t size) -{ - return hr_raid5_bd_op(HR_BD_WRITE, bd, ba, cnt, NULL, data, size); + /* XXX */ + return EOK; } -static errno_t hr_raid5_bd_get_block_size(bd_srv_t *bd, size_t *rsize) +static errno_t hr_raid5_bd_read_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt, + void *data_read, size_t size) { hr_volume_t *vol = bd->srvs->sarg; + errno_t rc; - *rsize = vol->bsize; - return EOK; -} + if (size < cnt * vol->bsize) + return EINVAL; -static errno_t hr_raid5_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb) -{ - hr_volume_t *vol = bd->srvs->sarg; + fibril_rwlock_read_lock(&vol->states_lock); + hr_vol_state_t vol_state = vol->state; + fibril_rwlock_read_unlock(&vol->states_lock); - *rnb = vol->data_blkno; - return EOK; -} + if (vol_state == HR_VOL_FAULTY || vol_state == HR_VOL_NONE) + return EIO; -static errno_t hr_raid5_vol_usable(hr_volume_t *vol) -{ - if (vol->state == HR_VOL_ONLINE || - vol->state == HR_VOL_DEGRADED || - vol->state == HR_VOL_REBUILD) - return EOK; - return EIO; -} + rc = hr_check_ba_range(vol, cnt, ba); + if (rc != EOK) + return rc; -/* - * Returns (-1) if all extents are online, - * else returns index of first bad one. - */ -static ssize_t hr_raid5_get_bad_ext(hr_volume_t *vol) -{ - for (size_t i = 0; i < vol->extent_no; i++) - if (vol->extents[i].state != HR_EXT_ONLINE) - return i; - return -1; -} + uint64_t strip_size = vol->strip_size / vol->bsize; /* in blocks */ + uint64_t strip_no = ba / strip_size; -static errno_t hr_raid5_update_vol_state(hr_volume_t *vol) -{ - hr_vol_state_t old_state = vol->state; - size_t bad = 0; - for (size_t i = 0; i < vol->extent_no; i++) - if (vol->extents[i].state != HR_EXT_ONLINE) - bad++; + /* calculate number of stripes touched */ + uint64_t last_ba = ba + cnt - 1; + uint64_t end_strip_no = last_ba / strip_size; + uint64_t start_stripe = strip_no / (vol->extent_no - 1); + uint64_t end_stripe = end_strip_no / (vol->extent_no - 1); + size_t stripes_cnt = end_stripe - start_stripe + 1; - switch (bad) { - case 0: - if (old_state != HR_VOL_ONLINE) - hr_update_vol_state(vol, HR_VOL_ONLINE); - return EOK; - case 1: - if (old_state != HR_VOL_DEGRADED && - old_state != HR_VOL_REBUILD) { + hr_stripe_t *stripes = hr_create_stripes(vol, stripes_cnt, false); + if (stripes == NULL) + return ENOMEM; - hr_update_vol_state(vol, HR_VOL_DEGRADED); + /* + * Pre-allocate range locks, because after group creation and + * firing off IO requests there is no easy consistent ENOMEM error + * path. + */ + hr_range_lock_t **rlps = malloc_waitok(stripes_cnt * sizeof(*rlps)); + for (size_t i = 0; i < stripes_cnt; i++) + rlps[i] = malloc_waitok(sizeof(**rlps)); - if (vol->hotspare_no > 0) { - fid_t fib = fibril_create(hr_raid5_rebuild, - vol); - if (fib == 0) - return ENOMEM; - fibril_start(fib); - fibril_detach(fib); - } - } - return EOK; - default: - if (old_state != HR_VOL_FAULTY) - hr_update_vol_state(vol, HR_VOL_FAULTY); - return EIO; + /* + * extent order has to be locked for the whole IO duration, + * so that workers have consistent targets + */ + fibril_rwlock_read_lock(&vol->extents_lock); + + for (uint64_t s = start_stripe; s <= end_stripe; s++) { + uint64_t relative = s - start_stripe; + hr_range_lock_acquire_noalloc(rlps[relative], vol, s, 1); } -} -static void xor(void *dst, const void *src, size_t size) -{ - size_t i; - uint64_t *d = dst; - const uint64_t *s = src; + uint64_t phys_block, len; + size_t left; - for (i = 0; i < size / sizeof(uint64_t); ++i) - *d++ ^= *s++; -} + hr_layout_t layout = vol->layout; + hr_level_t level = vol->level; -static errno_t hr_raid5_read_degraded(hr_volume_t *vol, uint64_t bad, - uint64_t block, void *data, size_t cnt) -{ - errno_t rc; - size_t i; - void *xorbuf; - void *buf; - uint64_t len = vol->bsize * cnt; + /* parity extent */ + size_t p_extent = hr_raid5_parity_extent(level, layout, + vol->extent_no, strip_no); - xorbuf = malloc(len); - if (xorbuf == NULL) - return ENOMEM; + uint64_t strip_off = ba % strip_size; - buf = malloc(len); - if (buf == NULL) { - free(xorbuf); - return ENOMEM; - } + left = cnt; - /* read all other extents in the stripe */ - bool first = true; - for (i = 0; i < vol->extent_no; i++) { - if (i == bad) - continue; + while (left != 0) { + if (level == HR_LVL_5) { + p_extent = hr_raid5_parity_extent(level, layout, + vol->extent_no, strip_no); + } - if (first) { - rc = block_read_direct(vol->extents[i].svc_id, block, - cnt, xorbuf); - if (rc != EOK) - goto end; + size_t extent = hr_raid5_data_extent(level, layout, + vol->extent_no, strip_no, p_extent); - first = false; - } else { - rc = block_read_direct(vol->extents[i].svc_id, block, - cnt, buf); - if (rc != EOK) - goto end; - xor(xorbuf, buf, len); - } - } + uint64_t stripe_no = strip_no / (vol->extent_no - 1); + size_t relative_si = stripe_no - start_stripe; /* relative stripe index */ + hr_stripe_t *stripe = &stripes[relative_si]; + stripe->p_extent = p_extent; - memcpy(data, xorbuf, len); -end: - free(xorbuf); - free(buf); - return rc; -} + stripe->strips_touched++; -static errno_t hr_raid5_write(hr_volume_t *vol, uint64_t p_extent, - uint64_t extent, aoff64_t ba, const void *data, size_t cnt) -{ - errno_t rc; - size_t i; - void *xorbuf; - void *buf; - uint64_t len = vol->bsize * cnt; - - ssize_t bad = hr_raid5_get_bad_ext(vol); - if (bad == -1 || (size_t)bad == p_extent) { - rc = block_write_direct(vol->extents[extent].svc_id, ba, cnt, - data); - if (rc != EOK) - return rc; - /* - * DEGRADED parity - skip parity write - */ - if ((size_t)bad == p_extent) - return EOK; + phys_block = stripe_no * strip_size + strip_off; + cnt = min(left, strip_size - strip_off); + len = vol->bsize * cnt; + hr_add_data_offset(vol, &phys_block); - rc = hr_raid5_write_parity(vol, p_extent, extent, ba, data, - cnt); - return rc; + stripe->extent_span[extent].range.start = phys_block; + stripe->extent_span[extent].range.end = phys_block + cnt - 1; + stripe->extent_span[extent].cnt = cnt; + stripe->extent_span[extent].data_read = data_read; + stripe->extent_span[extent].strip_off = strip_off; + + data_read += len; + left -= cnt; + strip_off = 0; + strip_no++; } - xorbuf = malloc(len); - if (xorbuf == NULL) - return ENOMEM; +retry: + size_t bad_extent = vol->extent_no; - buf = malloc(len); - if (buf == NULL) { - free(xorbuf); - return ENOMEM; - } + uint64_t rebuild_pos = atomic_load_explicit(&vol->rebuild_blk, + memory_order_relaxed); - if (extent == (size_t)bad) { - /* - * new parity = read other and xor in new data - * - * write new parity - */ - bool first = true; - for (i = 0; i < vol->extent_no; i++) { - if (i == (size_t)bad) - continue; - if (i == p_extent) - continue; - if (first) { - rc = block_read_direct(vol->extents[i].svc_id, - ba, cnt, xorbuf); - if (rc != EOK) - goto end; + fibril_rwlock_read_lock(&vol->states_lock); - first = false; - } else { - rc = block_read_direct(vol->extents[i].svc_id, - ba, cnt, buf); - if (rc != EOK) - goto end; - xor(xorbuf, buf, len); - } + for (size_t e = 0; e < vol->extent_no; e++) { + hr_ext_state_t s = vol->extents[e].state; + if ((vol->state == HR_VOL_DEGRADED && s != HR_EXT_ONLINE) || + (s == HR_EXT_REBUILD && rebuild_pos < start_stripe)) { + bad_extent = e; + break; } - xor(xorbuf, data, len); - rc = block_write_direct(vol->extents[p_extent].svc_id, ba, cnt, - xorbuf); - if (rc != EOK) - goto end; - } else { - /* - * new parity = xor original data and old parity and new data - * - * write parity, new data - */ - rc = block_read_direct(vol->extents[extent].svc_id, ba, cnt, - xorbuf); - if (rc != EOK) - goto end; - rc = block_read_direct(vol->extents[p_extent].svc_id, ba, cnt, - buf); - if (rc != EOK) - goto end; + } - xor(xorbuf, buf, len); + fibril_rwlock_read_unlock(&vol->states_lock); - xor(xorbuf, data, len); + for (size_t s = 0; s < stripes_cnt; s++) { + if (stripes[s].done) + continue; + execute_stripe(&stripes[s], bad_extent); + } - rc = block_write_direct(vol->extents[p_extent].svc_id, ba, cnt, - xorbuf); - if (rc != EOK) - goto end; - rc = block_write_direct(vol->extents[extent].svc_id, ba, cnt, - data); - if (rc != EOK) - goto end; + for (size_t s = 0; s < stripes_cnt; s++) { + if (stripes[s].done) + continue; + wait_for_stripe(&stripes[s]); } -end: - free(xorbuf); - free(buf); - return rc; -} -static errno_t hr_raid5_write_parity(hr_volume_t *vol, uint64_t p_extent, - uint64_t extent, uint64_t block, const void *data, size_t cnt) -{ - errno_t rc; - size_t i; - void *xorbuf; - void *buf; - uint64_t len = vol->bsize * cnt; + hr_raid5_vol_state_eval(vol); - xorbuf = malloc(len); - if (xorbuf == NULL) - return ENOMEM; + rc = EOK; - buf = malloc(len); - if (buf == NULL) { - free(xorbuf); - return ENOMEM; + fibril_rwlock_read_lock(&vol->states_lock); + + if (vol->state == HR_VOL_FAULTY) { + fibril_rwlock_read_unlock(&vol->states_lock); + rc = EIO; + goto end; } - bool first = true; - for (i = 0; i < vol->extent_no; i++) { - if (i == p_extent) - continue; + fibril_rwlock_read_unlock(&vol->states_lock); - if (first) { - if (i == extent) { - memcpy(xorbuf, data, len); - } else { - rc = block_read_direct(vol->extents[i].svc_id, - block, cnt, xorbuf); - if (rc != EOK) - goto end; - } + for (size_t s = 0; s < stripes_cnt; s++) + if (stripes[s].rc == EAGAIN) + goto retry; - first = false; - } else { - if (i == extent) { - xor(xorbuf, data, len); - } else { - rc = block_read_direct(vol->extents[i].svc_id, - block, cnt, buf); - if (rc != EOK) - goto end; + /* all stripes are done */ +end: + fibril_rwlock_read_unlock(&vol->extents_lock); - xor(xorbuf, buf, len); - } - } - } + for (size_t i = 0; i < stripes_cnt; i++) + hr_range_lock_release(rlps[i]); + + hr_destroy_stripes(stripes, stripes_cnt); - rc = block_write_direct(vol->extents[p_extent].svc_id, block, cnt, - xorbuf); -end: - free(xorbuf); - free(buf); return rc; } -static errno_t hr_raid5_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, - size_t cnt, void *dst, const void *src, size_t size) +static errno_t hr_raid5_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, + const void *data_write, size_t size) { hr_volume_t *vol = bd->srvs->sarg; errno_t rc; - uint64_t phys_block, len; - size_t left; - const uint8_t *data_write = src; - uint8_t *data_read = dst; - /* propagate sync */ - if (type == HR_BD_SYNC && ba == 0 && cnt == 0) { - hr_sync_all_extents(vol); - rc = hr_raid5_update_vol_state(vol); - return rc; - } + if (size < cnt * vol->bsize) + return EINVAL; + + fibril_rwlock_read_lock(&vol->states_lock); + hr_vol_state_t vol_state = vol->state; + fibril_rwlock_read_unlock(&vol->states_lock); - if (type == HR_BD_READ || type == HR_BD_WRITE) - if (size < cnt * vol->bsize) - return EINVAL; + if (vol_state == HR_VOL_FAULTY || vol_state == HR_VOL_NONE) + return EIO; + + /* increment metadata counter only on first write */ + bool exp = false; + if (atomic_compare_exchange_strong(&vol->first_write, &exp, true)) { + vol->meta_ops->inc_counter(vol); + vol->meta_ops->save(vol, WITH_STATE_CALLBACK); + } rc = hr_check_ba_range(vol, cnt, ba); if (rc != EOK) return rc; - hr_layout_t layout = vol->layout; - hr_level_t level = vol->level; - uint64_t strip_size = vol->strip_size / vol->bsize; /* in blocks */ - uint64_t stripe = (ba / strip_size); /* stripe number */ + uint64_t strip_no = ba / strip_size; - /* parity extent */ - uint64_t p_extent; - if (level == HR_LVL_4 && layout == HR_LAYOUT_RAID4_0) { - p_extent = 0; - } else if (level == HR_LVL_4 && layout == HR_LAYOUT_RAID4_N) { - p_extent = vol->extent_no - 1; - } else if (level == HR_LVL_5 && layout == HR_LAYOUT_RAID5_0R) { - p_extent = (stripe / (vol->extent_no - 1)) % vol->extent_no; - } else if (level == HR_LVL_5 && - (layout == HR_LAYOUT_RAID5_NR || layout == HR_LAYOUT_RAID5_NC)) { - p_extent = (vol->extent_no - 1) - - (stripe / (vol->extent_no - 1)) % vol->extent_no; - } else { - return EINVAL; - } + /* calculate number of stripes touched */ + uint64_t last_ba = ba + cnt - 1; + uint64_t end_strip_no = last_ba / strip_size; + uint64_t start_stripe = strip_no / (vol->extent_no - 1); + uint64_t end_stripe = end_strip_no / (vol->extent_no - 1); + size_t stripes_cnt = end_stripe - start_stripe + 1; + + hr_stripe_t *stripes = hr_create_stripes(vol, stripes_cnt, true); + if (stripes == NULL) + return ENOMEM; + + uint64_t stripe_size = strip_size * (vol->extent_no - 1); + + for (uint64_t stripe = start_stripe; stripe <= end_stripe; stripe++) { + uint64_t relative_stripe = stripe - start_stripe; + + uint64_t s_start = stripe * stripe_size; + uint64_t s_end = s_start + stripe_size - 1; - uint64_t extent; - if (level == HR_LVL_4 && layout == HR_LAYOUT_RAID4_0) { - extent = (stripe % (vol->extent_no - 1)) + 1; - } else if (level == HR_LVL_4 && layout == HR_LAYOUT_RAID4_N) { - extent = stripe % (vol->extent_no - 1); - } else if (level == HR_LVL_5 && - (layout == HR_LAYOUT_RAID5_0R || layout == HR_LAYOUT_RAID5_NR)) { - if ((stripe % (vol->extent_no - 1)) < p_extent) - extent = stripe % (vol->extent_no - 1); + uint64_t overlap_start; + if (ba > s_start) + overlap_start = ba; else - extent = (stripe % (vol->extent_no - 1)) + 1; - } else if (level == HR_LVL_5 && layout == HR_LAYOUT_RAID5_NC) { - extent = - ((stripe % (vol->extent_no - 1)) + p_extent + 1) % - vol->extent_no; - } else { - return EINVAL; + overlap_start = s_start; + + uint64_t overlap_end; + if (last_ba < s_end) + overlap_end = last_ba; + else + overlap_end = s_end; + + uint64_t start_strip_index = + (overlap_start - s_start) / strip_size; + uint64_t end_strip_index = (overlap_end - s_start) / strip_size; + size_t strips_touched = end_strip_index - start_strip_index + 1; + + stripes[relative_stripe].strips_touched = strips_touched; + + uint64_t first_offset = (overlap_start - s_start) % strip_size; + uint64_t last_offset = (overlap_end - s_start) % strip_size; + + size_t partials = 0; + if (first_offset != 0) + partials++; + if (last_offset != strip_size - 1) + partials++; + if (start_strip_index == end_strip_index && partials == 2) + partials = 1; + + stripes[relative_stripe].strips_touched = strips_touched; + stripes[relative_stripe].partial_strips_touched = partials; + + if (strips_touched < (vol->extent_no - 1) / 2) + stripes[relative_stripe].subtract = true; } - uint64_t ext_stripe = stripe / (vol->extent_no - 1); /* stripe level */ - uint64_t strip_off = ba % strip_size; /* strip offset */ + /* + * Pre-allocate range locks, because after group creation and + * firing off IO requests there is no easy consistent ENOMEM error + * path. + */ + hr_range_lock_t **rlps = malloc_waitok(stripes_cnt * sizeof(*rlps)); + for (size_t i = 0; i < stripes_cnt; i++) + rlps[i] = malloc_waitok(sizeof(**rlps)); - fibril_mutex_lock(&vol->lock); + /* + * extent order has to be locked for the whole IO duration, + * so that workers have consistent targets + */ + fibril_rwlock_read_lock(&vol->extents_lock); - rc = hr_raid5_vol_usable(vol); - if (rc != EOK) { - fibril_mutex_unlock(&vol->lock); - return EIO; + for (uint64_t s = start_stripe; s <= end_stripe; s++) { + uint64_t relative = s - start_stripe; + hr_range_lock_acquire_noalloc(rlps[relative], vol, s, 1); } + uint64_t phys_block, len; + size_t left; + + hr_layout_t layout = vol->layout; + hr_level_t level = vol->level; + + /* parity extent */ + size_t p_extent = hr_raid5_parity_extent(level, layout, + vol->extent_no, strip_no); + + uint64_t strip_off = ba % strip_size; + left = cnt; - fibril_rwlock_write_lock(&vol->states_lock); while (left != 0) { - phys_block = ext_stripe * strip_size + strip_off; + if (level == HR_LVL_5) { + p_extent = hr_raid5_parity_extent(level, layout, + vol->extent_no, strip_no); + } + + size_t extent = hr_raid5_data_extent(level, layout, + vol->extent_no, strip_no, p_extent); + + uint64_t stripe_no = strip_no / (vol->extent_no - 1); + size_t relative_si = stripe_no - start_stripe; /* relative stripe index */ + hr_stripe_t *stripe = &stripes[relative_si]; + stripe->p_extent = p_extent; + + phys_block = stripe_no * strip_size + strip_off; cnt = min(left, strip_size - strip_off); len = vol->bsize * cnt; - hr_add_ba_offset(vol, &phys_block); - switch (type) { - case HR_BD_SYNC: - if (vol->extents[extent].state != HR_EXT_ONLINE) - break; - rc = block_sync_cache(vol->extents[extent].svc_id, - phys_block, cnt); - /* allow unsupported sync */ - if (rc == ENOTSUP) - rc = EOK; - break; - case HR_BD_READ: - retry_read: - ssize_t bad = hr_raid5_get_bad_ext(vol); - if (bad > -1 && extent == (size_t)bad) { - rc = hr_raid5_read_degraded(vol, bad, - phys_block, data_read, cnt); - } else { - rc = block_read_direct(vol->extents[extent].svc_id, - phys_block, cnt, data_read); - } - data_read += len; - break; - case HR_BD_WRITE: - retry_write: - rc = hr_raid5_write(vol, p_extent, extent, phys_block, - data_write, cnt); - data_write += len; + hr_add_data_offset(vol, &phys_block); + + stripe->extent_span[extent].range.start = phys_block; + stripe->extent_span[extent].range.end = phys_block + cnt - 1; + stripe->extent_span[extent].cnt = cnt; + stripe->extent_span[extent].data_write = data_write; + stripe->extent_span[extent].strip_off = strip_off; + + data_write += len; + left -= cnt; + strip_off = 0; + strip_no++; + } + +retry: + size_t bad_extent = vol->extent_no; + + uint64_t rebuild_pos = atomic_load_explicit(&vol->rebuild_blk, + memory_order_relaxed); + + fibril_rwlock_read_lock(&vol->states_lock); + + for (size_t e = 0; e < vol->extent_no; e++) { + hr_ext_state_t s = vol->extents[e].state; + if ((vol->state == HR_VOL_DEGRADED && s != HR_EXT_ONLINE) || + (s == HR_EXT_REBUILD && rebuild_pos < start_stripe)) { + bad_extent = e; break; - default: - rc = EINVAL; - goto error; } + } - if (rc == ENOMEM) - goto error; + fibril_rwlock_read_unlock(&vol->states_lock); - hr_raid5_ext_state_cb(vol, extent, rc); + for (size_t s = 0; s < stripes_cnt; s++) { + if (stripes[s].done) + continue; + execute_stripe(&stripes[s], bad_extent); + } - if (rc != EOK) { - rc = hr_raid5_update_vol_state(vol); - if (rc == EOK) { - /* - * State changed from ONLINE -> DEGRADED, - * rewind and retry - */ - if (type == HR_BD_WRITE) { - data_write -= len; - goto retry_write; - } else if (type == HR_BD_WRITE) { - data_read -= len; - goto retry_read; - } - } else { - rc = EIO; - goto error; + for (size_t s = 0; s < stripes_cnt; s++) { + if (stripes[s].done) + continue; + wait_for_stripe(&stripes[s]); + } + + hr_raid5_vol_state_eval(vol); + + rc = EOK; + + fibril_rwlock_read_lock(&vol->states_lock); + + if (vol->state == HR_VOL_FAULTY) { + fibril_rwlock_read_unlock(&vol->states_lock); + rc = EIO; + goto end; + } + + fibril_rwlock_read_unlock(&vol->states_lock); + + for (size_t s = 0; s < stripes_cnt; s++) + if (stripes[s].rc == EAGAIN) + goto retry; + + /* all stripes are done */ +end: + fibril_rwlock_read_unlock(&vol->extents_lock); + + for (size_t i = 0; i < stripes_cnt; i++) + hr_range_lock_release(rlps[i]); + + hr_destroy_stripes(stripes, stripes_cnt); + + return rc; +} + +static errno_t hr_raid5_bd_get_block_size(bd_srv_t *bd, size_t *rsize) +{ + hr_volume_t *vol = bd->srvs->sarg; + + *rsize = vol->bsize; + return EOK; +} + +static errno_t hr_raid5_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb) +{ + hr_volume_t *vol = bd->srvs->sarg; + + *rnb = vol->data_blkno; + return EOK; +} + +static void hr_raid5_vol_state_eval_forced(hr_volume_t *vol) +{ + fibril_rwlock_read_lock(&vol->extents_lock); + fibril_rwlock_write_lock(&vol->states_lock); + + hr_vol_state_t state = vol->state; + + size_t bad = 0; + for (size_t i = 0; i < vol->extent_no; i++) + if (vol->extents[i].state != HR_EXT_ONLINE) + bad++; + + switch (bad) { + case 0: + if (state != HR_VOL_ONLINE) + hr_update_vol_state(vol, HR_VOL_ONLINE); + break; + case 1: + if (state != HR_VOL_DEGRADED && state != HR_VOL_REBUILD) + hr_update_vol_state(vol, HR_VOL_DEGRADED); + + if (state != HR_VOL_REBUILD) { + /* XXX: allow REBUILD on INVALID extents */ + fibril_mutex_lock(&vol->hotspare_lock); + size_t hs_no = vol->hotspare_no; + fibril_mutex_unlock(&vol->hotspare_lock); + if (hs_no > 0) { + fid_t fib = fibril_create(hr_raid5_rebuild, + vol); + if (fib == 0) + break; + fibril_start(fib); + fibril_detach(fib); } } + break; + default: + if (state != HR_VOL_FAULTY) + hr_update_vol_state(vol, HR_VOL_FAULTY); + break; + } - left -= cnt; - strip_off = 0; - stripe++; + fibril_rwlock_write_unlock(&vol->states_lock); + fibril_rwlock_read_unlock(&vol->extents_lock); +} - ext_stripe = stripe / (vol->extent_no - 1); /* stripe level */ +static void xor(void *dst, const void *src, size_t size) +{ + size_t i; + uint64_t *d = dst; + const uint64_t *s = src; + + for (i = 0; i < size / sizeof(uint64_t); ++i) + *d++ ^= *s++; +} - if (level == HR_LVL_5 && layout == HR_LAYOUT_RAID5_0R) { - p_extent = - (stripe / (vol->extent_no - 1)) % vol->extent_no; - } else if (level == HR_LVL_5 && - (layout == HR_LAYOUT_RAID5_NR || layout == HR_LAYOUT_RAID5_NC)) { - p_extent = (vol->extent_no - 1) - - (stripe / (vol->extent_no - 1)) % vol->extent_no; +static size_t hr_raid5_parity_extent(hr_level_t level, + hr_layout_t layout, size_t extent_no, uint64_t strip_no) +{ + switch (level) { + case HR_LVL_4: + switch (layout) { + case HR_LAYOUT_RAID4_0: + return (0); + case HR_LAYOUT_RAID4_N: + return (extent_no - 1); + default: + assert(0 && "invalid layout configuration"); } + case HR_LVL_5: + switch (layout) { + case HR_LAYOUT_RAID5_0R: + return ((strip_no / (extent_no - 1)) % extent_no); + case HR_LAYOUT_RAID5_NR: + case HR_LAYOUT_RAID5_NC: + return ((extent_no - 1) - + (strip_no / (extent_no - 1)) % extent_no); + default: + assert(0 && "invalid layout configuration"); + } + default: + assert(0 && "invalid layout configuration"); + } +} - if (level == HR_LVL_4 && layout == HR_LAYOUT_RAID4_0) { - extent = (stripe % (vol->extent_no - 1)) + 1; - } else if (level == HR_LVL_4 && layout == HR_LAYOUT_RAID4_N) { - extent = stripe % (vol->extent_no - 1); - } else if (level == HR_LVL_5 && - (layout == HR_LAYOUT_RAID5_0R || layout == HR_LAYOUT_RAID5_NR)) { - if ((stripe % (vol->extent_no - 1)) < p_extent) - extent = stripe % (vol->extent_no - 1); +static size_t hr_raid5_data_extent(hr_level_t level, + hr_layout_t layout, size_t extent_no, uint64_t strip_no, size_t p_extent) +{ + switch (level) { + case HR_LVL_4: + switch (layout) { + case HR_LAYOUT_RAID4_0: + return ((strip_no % (extent_no - 1)) + 1); + case HR_LAYOUT_RAID4_N: + return (strip_no % (extent_no - 1)); + default: + assert(0 && "invalid layout configuration"); + } + case HR_LVL_5: + switch (layout) { + case HR_LAYOUT_RAID5_0R: + case HR_LAYOUT_RAID5_NR: + if ((strip_no % (extent_no - 1)) < p_extent) + return (strip_no % (extent_no - 1)); else - extent = (stripe % (vol->extent_no - 1)) + 1; - } else if (level == HR_LVL_5 && layout == HR_LAYOUT_RAID5_NC) { - extent = - ((stripe % (vol->extent_no - 1)) + p_extent + 1) % - vol->extent_no; + return ((strip_no % (extent_no - 1)) + 1); + case HR_LAYOUT_RAID5_NC: + return (((strip_no % (extent_no - 1)) + p_extent + 1) % + extent_no); + default: + assert(0 && "invalid layout configuration"); } + default: + assert(0 && "invalid layout configuration"); } - -error: - (void)hr_raid5_update_vol_state(vol); - fibril_rwlock_write_unlock(&vol->states_lock); - fibril_mutex_unlock(&vol->lock); - return rc; } static errno_t hr_raid5_rebuild(void *arg) @@ -720,7 +737,6 @@ static errno_t hr_raid5_rebuild(void *arg) errno_t rc = EOK; void *buf = NULL, *xorbuf = NULL; - fibril_mutex_lock(&vol->lock); fibril_rwlock_read_lock(&vol->extents_lock); fibril_rwlock_write_lock(&vol->states_lock); @@ -784,7 +800,7 @@ static errno_t hr_raid5_rebuild(void *arg) xorbuf = malloc(max_blks * vol->bsize); uint64_t ba = 0, cnt; - hr_add_ba_offset(vol, &ba); + hr_add_data_offset(vol, &ba); while (left != 0) { cnt = min(left, max_blks); @@ -851,20 +867,17 @@ static errno_t hr_raid5_rebuild(void *arg) fibril_rwlock_write_unlock(&vol->states_lock); fibril_rwlock_read_unlock(&vol->extents_lock); - fibril_mutex_unlock(&vol->lock); rc = vol->meta_ops->save(vol, WITH_STATE_CALLBACK); - fibril_mutex_lock(&vol->lock); fibril_rwlock_read_lock(&vol->extents_lock); fibril_rwlock_write_lock(&vol->states_lock); end: - (void)hr_raid5_update_vol_state(vol); + hr_raid5_vol_state_eval_forced(vol); fibril_rwlock_write_unlock(&vol->states_lock); fibril_rwlock_read_unlock(&vol->extents_lock); - fibril_mutex_unlock(&vol->lock); if (buf != NULL) free(buf); diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 3a74311956..c4ed3126ea 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -149,7 +149,11 @@ errno_t hr_create_vol_struct(hr_volume_t **rvol, hr_level_t level, goto error; } - vol->fge = hr_fpool_create(16, 32, sizeof(hr_io_t)); + if (level == HR_LVL_4 || level == HR_LVL_5) + vol->fge = hr_fpool_create(16, 32, sizeof(hr_io_raid5_t)); + else + vol->fge = hr_fpool_create(16, 32, sizeof(hr_io_t)); + if (vol->fge == NULL) { rc = ENOMEM; goto error; @@ -164,8 +168,6 @@ errno_t hr_create_vol_struct(hr_volume_t **rvol, hr_level_t level, vol->state = HR_VOL_NONE; - fibril_mutex_initialize(&vol->lock); /* XXX: will remove this */ - fibril_mutex_initialize(&vol->md_lock); fibril_rwlock_initialize(&vol->extents_lock); @@ -497,34 +499,6 @@ void hr_update_hotspare_svc_id(hr_volume_t *vol, size_t hs_idx, vol->hotspares[hs_idx].svc_id = new; } -/* - * Do a whole sync (ba = 0, cnt = 0) across all extents, - * and update extent state. *For now*, the caller has to - * update volume state after the syncs. - * - * TODO: add update_vol_state fcn ptr for each raid - */ -void hr_sync_all_extents(hr_volume_t *vol) -{ - errno_t rc; - - fibril_mutex_lock(&vol->lock); - for (size_t i = 0; i < vol->extent_no; i++) { - if (vol->extents[i].state != HR_EXT_ONLINE) - continue; - rc = block_sync_cache(vol->extents[i].svc_id, 0, 0); - if (rc == ENOMEM || rc == ENOTSUP) - continue; - if (rc != EOK) { - if (rc == ENOENT) - hr_update_ext_state(vol, i, HR_EXT_MISSING); - else if (rc != EOK) - hr_update_ext_state(vol, i, HR_EXT_FAILED); - } - } - fibril_mutex_unlock(&vol->lock); -} - size_t hr_count_extents(hr_volume_t *vol, hr_ext_state_t state) { if (vol->level != HR_LVL_0) @@ -1115,5 +1089,15 @@ errno_t hr_util_add_hotspare(hr_volume_t *vol, service_id_t hotspare) return rc; } +void hr_raid5_xor(void *dst, const void *src, size_t size) +{ + size_t i; + uint64_t *d = dst; + const uint64_t *s = src; + + for (i = 0; i < size / sizeof(uint64_t); ++i) + *d++ ^= *s++; +} + /** @} */ diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index 8163de1958..0e1f231c61 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -109,6 +109,7 @@ extern hr_range_lock_t *hr_range_lock_acquire(hr_volume_t *, uint64_t, extern void hr_range_lock_release(hr_range_lock_t *); extern errno_t hr_util_try_assemble(hr_config_t *, size_t *); extern errno_t hr_util_add_hotspare(hr_volume_t *, service_id_t); +extern void hr_raid5_xor(void *, const void *, size_t); #endif diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index f5bbc6c9bd..00eb48152e 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -51,6 +51,7 @@ struct hr_volume; typedef struct hr_volume hr_volume_t; +typedef struct hr_stripe hr_stripe_t; typedef struct hr_metadata hr_metadata_t; typedef struct hr_superblock_ops hr_superblock_ops_t; @@ -68,9 +69,9 @@ typedef struct hr_volume { bd_srvs_t hr_bds; /* block interface to the vol */ service_id_t svc_id; /* service id */ - fibril_mutex_t lock; /* XXX: gone after para */ list_t range_lock_list; /* list of range locks */ fibril_mutex_t range_lock_list_lock; /* range locks list lock */ + hr_fpool_t *fge; /* fibril pool */ void *in_mem_md; From 137f7cf58375f85f3ac5e28c36138b283c3b76d8 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Wed, 18 Jun 2025 00:04:20 +0200 Subject: [PATCH 259/324] hr: add common hr_sync_extents() fcn --- uspace/srv/bd/hr/hr.c | 4 ++-- uspace/srv/bd/hr/raid0.c | 4 +++- uspace/srv/bd/hr/raid1.c | 5 +++-- uspace/srv/bd/hr/raid5.c | 5 +++-- uspace/srv/bd/hr/util.c | 32 ++++++++++++++++++++++++++++++++ uspace/srv/bd/hr/util.h | 1 + 6 files changed, 44 insertions(+), 7 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 4a42c45bf4..6f8b6049bf 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -353,11 +353,11 @@ static void hr_fail_extent_srv(ipc_call_t *icall) return; } - hr_extent_t *ext = &vol->extents[extent_idx_to_fail]; - fibril_rwlock_read_lock(&vol->extents_lock); fibril_rwlock_write_lock(&vol->states_lock); + hr_extent_t *ext = &vol->extents[extent_idx_to_fail]; + switch (ext->state) { case HR_EXT_NONE: case HR_EXT_MISSING: diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index 183bdc01b0..8c0adc34d5 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -207,7 +207,9 @@ static errno_t hr_raid0_bd_close(bd_srv_t *bd) static errno_t hr_raid0_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) { - return hr_raid0_bd_op(HR_BD_SYNC, bd, ba, cnt, NULL, NULL, 0); + hr_volume_t *vol = bd->srvs->sarg; + + return hr_sync_extents(vol); } static errno_t hr_raid0_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 09c7443893..8692a49bc1 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -262,7 +262,9 @@ static errno_t hr_raid1_bd_close(bd_srv_t *bd) static errno_t hr_raid1_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) { - return hr_raid1_bd_op(HR_BD_SYNC, bd, ba, cnt, NULL, NULL, 0); + hr_volume_t *vol = bd->srvs->sarg; + + return hr_sync_extents(vol); } static errno_t hr_raid1_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, @@ -309,7 +311,6 @@ static size_t hr_raid1_count_good_extents(hr_volume_t *vol, uint64_t ba, } return count; - } static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 668efd5d5a..00c347f487 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -218,8 +218,9 @@ static errno_t hr_raid5_bd_close(bd_srv_t *bd) static errno_t hr_raid5_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) { - /* XXX */ - return EOK; + hr_volume_t *vol = bd->srvs->sarg; + + return hr_sync_extents(vol); } static errno_t hr_raid5_bd_read_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt, diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index c4ed3126ea..433e8f6984 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -1099,5 +1099,37 @@ void hr_raid5_xor(void *dst, const void *src, size_t size) *d++ ^= *s++; } +errno_t hr_sync_extents(hr_volume_t *vol) +{ + errno_t rc = EOK; + + fibril_rwlock_read_lock(&vol->extents_lock); + for (size_t e = 0; e < vol->extent_no; e++) { + fibril_rwlock_read_lock(&vol->states_lock); + hr_ext_state_t s = vol->extents[e].state; + fibril_rwlock_read_unlock(&vol->states_lock); + + service_id_t svc_id = vol->extents[e].svc_id; + + if (s == HR_EXT_ONLINE || s == HR_EXT_REBUILD) { + errno_t rc = hr_sync_cache(svc_id, 0, 0); + if (rc != EOK && rc != ENOTSUP) + vol->hr_ops.ext_state_cb(vol, e, rc); + } + } + fibril_rwlock_read_unlock(&vol->extents_lock); + + vol->hr_ops.vol_state_eval(vol); + + fibril_rwlock_read_lock(&vol->states_lock); + hr_vol_state_t s = vol->state; + fibril_rwlock_read_unlock(&vol->states_lock); + + if (s == HR_VOL_FAULTY) + rc = EIO; + + return rc; +} + /** @} */ diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index 0e1f231c61..0fb3e2862f 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -110,6 +110,7 @@ extern void hr_range_lock_release(hr_range_lock_t *); extern errno_t hr_util_try_assemble(hr_config_t *, size_t *); extern errno_t hr_util_add_hotspare(hr_volume_t *, service_id_t); extern void hr_raid5_xor(void *, const void *, size_t); +extern errno_t hr_sync_extents(hr_volume_t *); #endif From 3c518fcc12d443676d872955c8983bcabe0781f7 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Wed, 18 Jun 2025 00:31:01 +0200 Subject: [PATCH 260/324] hr: remove HR_BD_SYNC All syncs are now done with common util hr_sync_extents(). --- uspace/srv/bd/hr/raid0.c | 42 +++++----------------------------------- uspace/srv/bd/hr/raid1.c | 4 +--- uspace/srv/bd/hr/var.h | 1 - 3 files changed, 6 insertions(+), 41 deletions(-) diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index 8c0adc34d5..7341720020 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -252,6 +252,9 @@ static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, const uint8_t *data_write = src; uint8_t *data_read = dst; + if (size < cnt * vol->bsize) + return EINVAL; + fibril_rwlock_read_lock(&vol->states_lock); if (vol->state != HR_VOL_ONLINE) { fibril_rwlock_read_unlock(&vol->states_lock); @@ -259,39 +262,6 @@ static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, } fibril_rwlock_read_unlock(&vol->states_lock); - /* propagate sync */ - if (type == HR_BD_SYNC && ba == 0 && cnt == 0) { - hr_fgroup_t *group = hr_fgroup_create(vol->fge, - vol->extent_no); - if (group == NULL) - return ENOMEM; - - for (size_t i = 0; i < vol->extent_no; i++) { - hr_io_t *io = hr_fgroup_alloc(group); - io->extent = i; - io->ba = ba; - io->cnt = cnt; - io->type = type; - io->vol = vol; - - hr_fgroup_submit(group, hr_io_worker, io); - } - - size_t bad; - rc = hr_fgroup_wait(group, NULL, &bad); - if (rc == ENOMEM) - return ENOMEM; - - if (bad > 0) - return EIO; - - return EOK; - } - - if (type == HR_BD_READ || type == HR_BD_WRITE) - if (size < cnt * vol->bsize) - return EINVAL; - rc = hr_check_ba_range(vol, cnt, ba); if (rc != EOK) return rc; @@ -333,10 +303,8 @@ static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, if (left == 0) break; - if (type == HR_BD_READ) - data_read += len; - else if (type == HR_BD_WRITE) - data_write += len; + data_read += len; + data_write += len; strip_off = 0; extent++; diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 8692a49bc1..416285e398 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -346,9 +346,7 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, if (rc != EOK) return rc; - /* allow full dev sync */ - if (!(type == HR_BD_SYNC && ba == 0 && cnt == 0)) - hr_add_data_offset(vol, &ba); + hr_add_data_offset(vol, &ba); /* * extent order has to be locked for the whole IO duration, diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index 00eb48152e..8961829710 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -113,7 +113,6 @@ typedef struct hr_volume { } hr_volume_t; typedef enum { - HR_BD_SYNC, HR_BD_READ, HR_BD_WRITE } hr_bd_op_type_t; From f0360ecfb99bc8a4a3179cf549049d26d3986159 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Wed, 18 Jun 2025 00:33:02 +0200 Subject: [PATCH 261/324] hr: RAID 0, 1: use ENOMEM safe primitives --- uspace/srv/bd/hr/io.c | 83 ++++++++-------------------------------- uspace/srv/bd/hr/io.h | 3 +- uspace/srv/bd/hr/raid0.c | 6 +-- uspace/srv/bd/hr/raid1.c | 35 ++--------------- uspace/srv/bd/hr/raid5.c | 3 -- uspace/srv/bd/hr/util.c | 4 +- 6 files changed, 24 insertions(+), 110 deletions(-) diff --git a/uspace/srv/bd/hr/io.c b/uspace/srv/bd/hr/io.c index 93cb5594a2..0284497372 100644 --- a/uspace/srv/bd/hr/io.c +++ b/uspace/srv/bd/hr/io.c @@ -47,8 +47,6 @@ #include "util.h" #include "var.h" -static errno_t exec_io_op(hr_io_t *); - /** 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) @@ -94,25 +92,25 @@ errno_t hr_io_worker(void *arg) { hr_io_t *io = arg; - errno_t rc = exec_io_op(io); - - /* - * We don't have to invalidate extents who got ENOMEM - * on READ/SYNC. But when we get ENOMEM on a WRITE, we have - * to invalidate it, because there could have been - * other writes, there is no way to rollback. - */ - if (rc != EOK && (rc != ENOMEM || io->type == HR_BD_WRITE)) - io->vol->hr_ops.ext_state_cb(io->vol, io->extent, rc); - - return rc; -} + errno_t rc; + size_t e = io->extent; + hr_extent_t *extents = (hr_extent_t *)&io->vol->extents; -errno_t hr_io_worker_basic(void *arg) -{ - hr_io_t *io = arg; + 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); + } - errno_t rc = exec_io_op(io); + if (rc != EOK) + io->vol->hr_ops.ext_state_cb(io->vol, io->extent, rc); return rc; } @@ -321,52 +319,5 @@ errno_t hr_io_raid5_parity_writer(void *arg) return rc; } -static errno_t exec_io_op(hr_io_t *io) -{ - size_t ext_idx = io->extent; - hr_extent_t *extents = (hr_extent_t *)&io->vol->extents; - errno_t rc; - - const char *debug_type_str = NULL; - switch (io->type) { - case HR_BD_SYNC: - debug_type_str = "SYNC"; - break; - case HR_BD_READ: - debug_type_str = "READ"; - break; - case HR_BD_WRITE: - debug_type_str = "WRITE"; - break; - } - - HR_DEBUG("%s WORKER (%p) on extent: %zu, ba: %" PRIu64 ", " - "cnt: %" PRIu64 "\n", - debug_type_str, io, io->extent, io->ba, io->cnt); - - switch (io->type) { - case HR_BD_SYNC: - rc = block_sync_cache(extents[ext_idx].svc_id, - io->ba, io->cnt); - if (rc == ENOTSUP) - rc = EOK; - break; - case HR_BD_READ: - rc = block_read_direct(extents[ext_idx].svc_id, io->ba, - io->cnt, io->data_read); - break; - case HR_BD_WRITE: - rc = block_write_direct(extents[ext_idx].svc_id, io->ba, - io->cnt, io->data_write); - break; - default: - assert(0); - } - - HR_DEBUG("WORKER (%p) rc: %s\n", io, str_error(rc)); - - return rc; -} - /** @} */ diff --git a/uspace/srv/bd/hr/io.h b/uspace/srv/bd/hr/io.h index a16a88df8c..d0b1a14588 100644 --- a/uspace/srv/bd/hr/io.h +++ b/uspace/srv/bd/hr/io.h @@ -41,7 +41,7 @@ #include "util.h" typedef struct hr_io { - hr_bd_op_type_t type; /* read/write/sync */ + hr_bd_op_type_t type; /* read/write */ uint64_t ba; uint64_t cnt; void *data_read; @@ -66,7 +66,6 @@ extern errno_t hr_read_direct(service_id_t, uint64_t, size_t, void *); extern errno_t hr_sync_cache(service_id_t, uint64_t, size_t); extern errno_t hr_io_worker(void *); -extern errno_t hr_io_worker_basic(void *); extern errno_t hr_io_raid5_basic_reader(void *); extern errno_t hr_io_raid5_reader(void *); diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index 7341720020..c541a376b0 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -279,8 +279,6 @@ static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, size_t span = end_strip_no - strip_no + 1; hr_fgroup_t *group = hr_fgroup_create(vol->fge, span); - if (group == NULL) - return ENOMEM; while (left != 0) { phys_block = stripe * strip_size + strip_off; @@ -315,9 +313,7 @@ static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, } size_t bad; - rc = hr_fgroup_wait(group, NULL, &bad); - if (rc == ENOMEM && type == HR_BD_READ) - return ENOMEM; + (void)hr_fgroup_wait(group, NULL, &bad); if (bad > 0) return EIO; diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 416285e398..3bec7f3f95 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -173,9 +173,6 @@ void hr_raid1_ext_state_cb(hr_volume_t *vol, size_t extent, errno_t rc) fibril_rwlock_write_lock(&vol->states_lock); switch (rc) { - case ENOMEM: - hr_update_ext_state(vol, extent, HR_EXT_INVALID); - break; case ENOENT: hr_update_ext_state(vol, extent, HR_EXT_MISSING); break; @@ -371,15 +368,8 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, continue; } - rc = block_read_direct(vol->extents[i].svc_id, ba, cnt, + rc = hr_read_direct(vol->extents[i].svc_id, ba, cnt, data_read); - - if (rc == ENOMEM && i + 1 == vol->extent_no) - goto end; - - if (rc == ENOMEM) - continue; - if (rc != EOK) { hr_raid1_ext_state_cb(vol, i, rc); } else { @@ -388,15 +378,8 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, } } break; - case HR_BD_SYNC: case HR_BD_WRITE: - if (type == HR_BD_WRITE) { - rl = hr_range_lock_acquire(vol, ba, cnt); - if (rl == NULL) { - rc = ENOMEM; - goto end; - } - } + rl = hr_range_lock_acquire(vol, ba, cnt); fibril_rwlock_read_lock(&vol->states_lock); @@ -407,13 +390,6 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, rebuild_blk); hr_fgroup_t *group = hr_fgroup_create(vol->fge, good); - if (group == NULL) { - if (type == HR_BD_WRITE) - hr_range_lock_release(rl); - rc = ENOMEM; - fibril_rwlock_read_unlock(&vol->states_lock); - goto end; - } for (i = 0; i < vol->extent_no; i++) { if (vol->extents[i].state != HR_EXT_ONLINE && @@ -445,13 +421,11 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, (void)hr_fgroup_wait(group, &successful, NULL); - if (type == HR_BD_WRITE) - hr_range_lock_release(rl); + hr_range_lock_release(rl); break; default: - rc = EINVAL; - goto end; + assert(0); } if (successful > 0) @@ -459,7 +433,6 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, else rc = EIO; -end: fibril_rwlock_read_unlock(&vol->extents_lock); hr_raid1_vol_state_eval(vol); diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 00c347f487..f6c54dcc8b 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -179,9 +179,6 @@ void hr_raid5_ext_state_cb(hr_volume_t *vol, size_t extent, errno_t rc) fibril_rwlock_write_lock(&vol->states_lock); switch (rc) { - case ENOMEM: - hr_update_ext_state(vol, extent, HR_EXT_INVALID); - break; case ENOENT: hr_update_ext_state(vol, extent, HR_EXT_MISSING); break; diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 433e8f6984..3efebd7561 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -523,9 +523,7 @@ void hr_range_lock_acquire_noalloc(hr_range_lock_t *rl, hr_volume_t *vol, hr_range_lock_t *hr_range_lock_acquire(hr_volume_t *vol, uint64_t ba, uint64_t cnt) { - hr_range_lock_t *rl = malloc(sizeof(hr_range_lock_t)); - if (rl == NULL) - return NULL; + hr_range_lock_t *rl = malloc_waitok(sizeof(hr_range_lock_t)); return hr_range_lock_acquire_internal(rl, vol, ba, cnt); } From 817cb83fe1c286437cb5eb4f1ba96adfa421f124 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 20 Jun 2025 21:35:44 +0200 Subject: [PATCH 262/324] hr: update loc_service_register() calls --- uspace/srv/bd/hr/hr.c | 3 ++- uspace/srv/bd/hr/util.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 6f8b6049bf..a530a21bd9 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -646,7 +646,8 @@ int main(int argc, char **argv) return EEXIST; } - rc = loc_service_register(hr_srv, SERVICE_NAME_HR, &ctl_sid); + rc = loc_service_register(hr_srv, SERVICE_NAME_HR, fallback_port_id, + &ctl_sid); if (rc != EOK) { HR_ERROR("failed registering service: %s", str_error(rc)); return EEXIST; diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 3efebd7561..4e675ed290 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -389,7 +389,7 @@ errno_t hr_register_volume(hr_volume_t *vol) category_id_t cat_id; const char *devname = vol->devname; - rc = loc_service_register(hr_srv, devname, &new_id); + rc = loc_service_register(hr_srv, devname, fallback_port_id, &new_id); if (rc != EOK) { HR_ERROR("unable to register device \"%s\": %s\n", devname, str_error(rc)); From 4c103ee788983c2e5c1aa72a4fa01f0b179a8d90 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 20 Jun 2025 21:36:12 +0200 Subject: [PATCH 263/324] hr: util.c: remove debug print --- uspace/srv/bd/hr/util.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 4e675ed290..0325a15c26 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -531,8 +531,6 @@ hr_range_lock_t *hr_range_lock_acquire(hr_volume_t *vol, uint64_t ba, static hr_range_lock_t *hr_range_lock_acquire_internal(hr_range_lock_t *rl, hr_volume_t *vol, uint64_t ba, uint64_t cnt) { - printf("hr_range_lock_acquire_internal got: 0x%p\n", rl); - rl->vol = vol; rl->off = ba; rl->len = cnt; From cff23429785237a4927c0e233f8e2d64a4490a69 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 20 Jun 2025 23:55:19 +0200 Subject: [PATCH 264/324] hr: raid5.c: fix bad extent selection --- uspace/srv/bd/hr/raid5.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index f6c54dcc8b..1617325fcb 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -332,7 +332,7 @@ static errno_t hr_raid5_bd_read_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt, for (size_t e = 0; e < vol->extent_no; e++) { hr_ext_state_t s = vol->extents[e].state; if ((vol->state == HR_VOL_DEGRADED && s != HR_EXT_ONLINE) || - (s == HR_EXT_REBUILD && rebuild_pos < start_stripe)) { + (s == HR_EXT_REBUILD && end_stripe >= rebuild_pos)) { bad_extent = e; break; } @@ -544,7 +544,7 @@ static errno_t hr_raid5_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, for (size_t e = 0; e < vol->extent_no; e++) { hr_ext_state_t s = vol->extents[e].state; if ((vol->state == HR_VOL_DEGRADED && s != HR_EXT_ONLINE) || - (s == HR_EXT_REBUILD && rebuild_pos < start_stripe)) { + (s == HR_EXT_REBUILD && start_stripe > rebuild_pos)) { bad_extent = e; break; } From 81b4c79545567c0060aaff6312830eea7da3f6de Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sat, 21 Jun 2025 19:25:23 +0200 Subject: [PATCH 265/324] hr: rename malloc_waitok() to hr_malloc_waitok() --- uspace/srv/bd/hr/fge.c | 7 ++++--- uspace/srv/bd/hr/io.c | 4 ++-- uspace/srv/bd/hr/raid5.c | 8 ++++---- uspace/srv/bd/hr/util.c | 6 +++--- uspace/srv/bd/hr/util.h | 4 ++-- 5 files changed, 15 insertions(+), 14 deletions(-) diff --git a/uspace/srv/bd/hr/fge.c b/uspace/srv/bd/hr/fge.c index 33886620f7..f2a8fac044 100644 --- a/uspace/srv/bd/hr/fge.c +++ b/uspace/srv/bd/hr/fge.c @@ -139,7 +139,7 @@ hr_fgroup_t *hr_fgroup_create(hr_fpool_t *parent, size_t wu_cnt) { assert(wu_cnt > 0); - hr_fgroup_t *result = malloc_waitok(sizeof(hr_fgroup_t)); + hr_fgroup_t *result = hr_malloc_waitok(sizeof(hr_fgroup_t)); result->reserved_cnt = 0; result->own_mem = NULL; @@ -160,14 +160,15 @@ hr_fgroup_t *hr_fgroup_create(hr_fpool_t *parent, size_t wu_cnt) * the fallback storage. */ size_t taking = parent->wu_storage_free_count; - result->own_mem = malloc_waitok(parent->wu_size * (wu_cnt - taking)); + result->own_mem = + hr_malloc_waitok(parent->wu_size * (wu_cnt - taking)); result->reserved_cnt = taking; parent->wu_storage_free_count = 0; } if (result->reserved_cnt > 0) { result->memslots = - malloc_waitok(sizeof(size_t) * result->reserved_cnt); + hr_malloc_waitok(sizeof(size_t) * result->reserved_cnt); } fibril_mutex_unlock(&parent->lock); diff --git a/uspace/srv/bd/hr/io.c b/uspace/srv/bd/hr/io.c index 0284497372..7ac23645ce 100644 --- a/uspace/srv/bd/hr/io.c +++ b/uspace/srv/bd/hr/io.c @@ -233,7 +233,7 @@ errno_t hr_io_raid5_subtract_writer(void *arg) size_t ext_idx = io->extent; hr_extent_t *extents = (hr_extent_t *)&io->vol->extents; - uint8_t *data = malloc_waitok(io->cnt * io->vol->bsize); + 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) { @@ -279,7 +279,7 @@ errno_t hr_io_raid5_reconstruct_reader(void *arg) size_t ext_idx = io->extent; hr_extent_t *extents = (hr_extent_t *)&io->vol->extents; - uint8_t *data = malloc_waitok(io->cnt * io->vol->bsize); + uint8_t *data = hr_malloc_waitok(io->cnt * io->vol->bsize); rc = hr_write_direct(extents[ext_idx].svc_id, io->ba, io->cnt, data); if (rc != EOK) { diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 1617325fcb..8e58437cdb 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -259,9 +259,9 @@ static errno_t hr_raid5_bd_read_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt, * firing off IO requests there is no easy consistent ENOMEM error * path. */ - hr_range_lock_t **rlps = malloc_waitok(stripes_cnt * sizeof(*rlps)); + hr_range_lock_t **rlps = hr_malloc_waitok(stripes_cnt * sizeof(*rlps)); for (size_t i = 0; i < stripes_cnt; i++) - rlps[i] = malloc_waitok(sizeof(**rlps)); + rlps[i] = hr_malloc_waitok(sizeof(**rlps)); /* * extent order has to be locked for the whole IO duration, @@ -473,9 +473,9 @@ static errno_t hr_raid5_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, * firing off IO requests there is no easy consistent ENOMEM error * path. */ - hr_range_lock_t **rlps = malloc_waitok(stripes_cnt * sizeof(*rlps)); + hr_range_lock_t **rlps = hr_malloc_waitok(stripes_cnt * sizeof(*rlps)); for (size_t i = 0; i < stripes_cnt; i++) - rlps[i] = malloc_waitok(sizeof(**rlps)); + rlps[i] = hr_malloc_waitok(sizeof(**rlps)); /* * extent order has to be locked for the whole IO duration, diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 0325a15c26..7673fb1ef7 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -83,7 +83,7 @@ extern fibril_rwlock_t hr_volumes_lock; * * Return value is never NULL. */ -void *malloc_waitok(size_t size) +void *hr_malloc_waitok(size_t size) { void *ret; while ((ret = malloc(size)) == NULL) @@ -92,7 +92,7 @@ void *malloc_waitok(size_t size) return ret; } -void *calloc_waitok(size_t nmemb, size_t size) +void *hr_calloc_waitok(size_t nmemb, size_t size) { void *ret; while ((ret = calloc(nmemb, size)) == NULL) @@ -523,7 +523,7 @@ void hr_range_lock_acquire_noalloc(hr_range_lock_t *rl, hr_volume_t *vol, hr_range_lock_t *hr_range_lock_acquire(hr_volume_t *vol, uint64_t ba, uint64_t cnt) { - hr_range_lock_t *rl = malloc_waitok(sizeof(hr_range_lock_t)); + hr_range_lock_t *rl = hr_malloc_waitok(sizeof(hr_range_lock_t)); return hr_range_lock_acquire_internal(rl, vol, ba, cnt); } diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index 0fb3e2862f..fbacda45fe 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -76,10 +76,10 @@ typedef struct hr_range_lock { bool ignore; /* prot. by vol->range_lock_list_lock */ } hr_range_lock_t; -extern void *malloc_waitok(size_t) +extern void *hr_malloc_waitok(size_t) __attribute__((malloc)); -extern void *calloc_waitok(size_t, size_t) +extern void *hr_calloc_waitok(size_t, size_t) __attribute__((malloc)); extern errno_t hr_create_vol_struct(hr_volume_t **, hr_level_t, const char *, From 263a2389bec7ca7beeb3ae5120941863de218291 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 22 Jun 2025 09:26:20 +0200 Subject: [PATCH 266/324] hr: rename volume state ONLINE to OPTIMAL --- uspace/lib/device/include/hr.h | 2 +- uspace/lib/device/src/hr.c | 4 ++-- uspace/srv/bd/hr/raid0.c | 8 ++++---- uspace/srv/bd/hr/raid1.c | 6 +++--- uspace/srv/bd/hr/raid5.c | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index 825e3812d7..d27b39fa78 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -65,7 +65,7 @@ typedef enum hr_layout { typedef enum hr_vol_state { HR_VOL_NONE = 0, /* Unknown/None */ - HR_VOL_ONLINE, /* optimal */ + HR_VOL_OPTIMAL, /* optimal */ HR_VOL_FAULTY, /* unusable */ HR_VOL_DEGRADED, /* not optimal */ HR_VOL_REBUILD /* rebuild in progress */ diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index 0c9fd9b2f6..81ed03715d 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -445,8 +445,8 @@ const char *hr_get_vol_state_str(hr_vol_state_t state) switch (state) { case HR_VOL_NONE: return "NONE/UNKNOWN"; - case HR_VOL_ONLINE: - return "ONLINE"; + case HR_VOL_OPTIMAL: + return "OPTIMAL"; case HR_VOL_FAULTY: return "FAULTY"; case HR_VOL_DEGRADED: diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index c541a376b0..e5e1ce06ba 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -91,7 +91,7 @@ errno_t hr_raid0_create(hr_volume_t *new_volume) } hr_raid0_vol_state_eval(new_volume); - if (new_volume->state != HR_VOL_ONLINE) { + if (new_volume->state != HR_VOL_OPTIMAL) { HR_NOTE("\"%s\": unusable state, not creating\n", new_volume->devname); return EINVAL; @@ -154,9 +154,9 @@ void hr_raid0_vol_state_eval(hr_volume_t *vol) fibril_rwlock_read_unlock(&vol->states_lock); - if (old_state != HR_VOL_ONLINE) { + if (old_state != HR_VOL_OPTIMAL) { fibril_rwlock_write_lock(&vol->states_lock); - hr_update_vol_state(vol, HR_VOL_ONLINE); + hr_update_vol_state(vol, HR_VOL_OPTIMAL); fibril_rwlock_write_unlock(&vol->states_lock); } } @@ -256,7 +256,7 @@ static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, return EINVAL; fibril_rwlock_read_lock(&vol->states_lock); - if (vol->state != HR_VOL_ONLINE) { + if (vol->state != HR_VOL_OPTIMAL) { fibril_rwlock_read_unlock(&vol->states_lock); return EIO; } diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 3bec7f3f95..c73bf70ec8 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -227,9 +227,9 @@ static void hr_raid1_vol_state_eval_forced(hr_volume_t *vol) } } } else { - if (old_state != HR_VOL_ONLINE) { + if (old_state != HR_VOL_OPTIMAL) { fibril_rwlock_write_lock(&vol->states_lock); - hr_update_vol_state(vol, HR_VOL_ONLINE); + hr_update_vol_state(vol, HR_VOL_OPTIMAL); fibril_rwlock_write_unlock(&vol->states_lock); } } @@ -525,7 +525,7 @@ static errno_t hr_raid1_rebuild(void *arg) * function will pick them up, and set the volume * state accordingly. */ - hr_update_vol_state(vol, HR_VOL_ONLINE); + hr_update_vol_state(vol, HR_VOL_OPTIMAL); hr_mark_vol_state_dirty(vol); fibril_rwlock_write_unlock(&vol->states_lock); diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 8e58437cdb..d2dc17bdc9 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -624,8 +624,8 @@ static void hr_raid5_vol_state_eval_forced(hr_volume_t *vol) switch (bad) { case 0: - if (state != HR_VOL_ONLINE) - hr_update_vol_state(vol, HR_VOL_ONLINE); + if (state != HR_VOL_OPTIMAL) + hr_update_vol_state(vol, HR_VOL_OPTIMAL); break; case 1: if (state != HR_VOL_DEGRADED && state != HR_VOL_REBUILD) From c2d737df2fbcffe4d14f250f3692beb2df806e9c Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 22 Jun 2025 18:31:42 +0200 Subject: [PATCH 267/324] hrctl: allow --help even when the server is offline --- uspace/app/hrctl/hrctl.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index 49eac43219..58422bb162 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -128,6 +128,13 @@ int main(int argc, char **argv) goto end; } + if (argc > 1 && + ((str_cmp(argv[1], "-h") == 0) || + str_cmp(argv[1], "--help") == 0)) { + usage(); + return EXIT_SUCCESS; + } + rc = hr_sess_init(&hr); if (rc != EOK) { printf(NAME ": hr server session init failed: %s\n", @@ -177,6 +184,7 @@ int main(int argc, char **argv) if (rc != EXIT_SUCCESS) printf(NAME ": use --help to see usage\n"); + return rc; } From 8b0fbb7d05893339dbc227c6c6237dd0d14add07 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 22 Jun 2025 18:32:15 +0200 Subject: [PATCH 268/324] hrctl: update usage message --- uspace/app/hrctl/hrctl.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index 58422bb162..1fb597d63c 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -107,16 +107,16 @@ static const char usage_str[] = "\t\thrctl -s\n" "\n" "Notes:\n" - " Volume service names are automatically prepended with \"devices/\" prefix.\n" " Simulating an extent failure with -m volume -f index is dangerous. It marks\n" - " metadata as dirty in other healthy extents, and therefore invalidates\n" - " the specified extent.\n" - " Nested levels have to be created manually, or from config file, but need to\n" + " metadata as dirty in other healthy extents, and zeroes out the superblock\n" + " on the specified extent.\n" + " Nested levels have to be created manually, or from a config file, and need to\n" " be specified as separate volumes.\n" "\n" "Limitations:\n" "\t- volume name must be shorter than 32 characters\n" - "\t- automatic assembly and disassembly on nested volumes is UNDEFINED!\n"; + "\t- no explicit nested levels volume support\n" + "\t- automatic assembly and disassembly on nested volumes is undefine!\n"; int main(int argc, char **argv) { From 13f4c85424ec00177a917e17765ddcd622090436 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 23 Jun 2025 12:54:34 +0200 Subject: [PATCH 269/324] hr: raid1.c: allow rebuild on INVALID extents --- uspace/srv/bd/hr/raid1.c | 216 +++++++++++++-------------------------- 1 file changed, 72 insertions(+), 144 deletions(-) diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index c73bf70ec8..50e2e95d76 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -58,13 +58,11 @@ static void hr_raid1_vol_state_eval_forced(hr_volume_t *); static size_t hr_raid1_count_good_extents(hr_volume_t *, uint64_t, size_t, uint64_t); -static errno_t hr_raid1_bd_op(hr_bd_op_type_t, bd_srv_t *, aoff64_t, size_t, +static errno_t hr_raid1_bd_op(hr_bd_op_type_t, hr_volume_t *, aoff64_t, size_t, void *, const void *, size_t); static errno_t hr_raid1_rebuild(void *); static errno_t init_rebuild(hr_volume_t *, size_t *); static errno_t swap_hs(hr_volume_t *, size_t, size_t); -static errno_t hr_raid1_restore_blocks(hr_volume_t *, size_t, uint64_t, size_t, - void *); /* bdops */ static errno_t hr_raid1_bd_open(bd_srvs_t *, bd_srv_t *); @@ -195,6 +193,12 @@ static void hr_raid1_vol_state_eval_forced(hr_volume_t *vol) hr_vol_state_t old_state = vol->state; size_t healthy = hr_count_extents(vol, HR_EXT_ONLINE); + size_t invalid_no = hr_count_extents(vol, HR_EXT_INVALID); + + fibril_mutex_lock(&vol->hotspare_lock); + size_t hs_no = vol->hotspare_no; + fibril_mutex_unlock(&vol->hotspare_lock); + fibril_rwlock_read_unlock(&vol->states_lock); fibril_rwlock_read_unlock(&vol->extents_lock); @@ -213,11 +217,7 @@ static void hr_raid1_vol_state_eval_forced(hr_volume_t *vol) } if (old_state != HR_VOL_REBUILD) { - /* XXX: allow REBUILD on INVALID extents */ - fibril_mutex_lock(&vol->hotspare_lock); - size_t hs_no = vol->hotspare_no; - fibril_mutex_unlock(&vol->hotspare_lock); - if (hs_no > 0) { + if (hs_no > 0 || invalid_no > 0) { fid_t fib = fibril_create(hr_raid1_rebuild, vol); if (fib == 0) @@ -267,13 +267,17 @@ static errno_t hr_raid1_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt) static errno_t hr_raid1_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, void *buf, size_t size) { - return hr_raid1_bd_op(HR_BD_READ, bd, ba, cnt, buf, NULL, size); + hr_volume_t *vol = bd->srvs->sarg; + + return hr_raid1_bd_op(HR_BD_READ, vol, ba, cnt, buf, NULL, size); } static errno_t hr_raid1_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, const void *data, size_t size) { - return hr_raid1_bd_op(HR_BD_WRITE, bd, ba, cnt, NULL, data, size); + hr_volume_t *vol = bd->srvs->sarg; + + return hr_raid1_bd_op(HR_BD_WRITE, vol, ba, cnt, NULL, data, size); } static errno_t hr_raid1_bd_get_block_size(bd_srv_t *bd, size_t *rsize) @@ -310,12 +314,12 @@ static size_t hr_raid1_count_good_extents(hr_volume_t *vol, uint64_t ba, return count; } -static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, - size_t cnt, void *data_read, const void *data_write, size_t size) +static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, hr_volume_t *vol, + aoff64_t ba, size_t cnt, void *data_read, const void *data_write, + size_t size) { HR_DEBUG("%s()", __func__); - hr_volume_t *vol = bd->srvs->sarg; hr_range_lock_t *rl = NULL; errno_t rc; size_t i; @@ -451,23 +455,27 @@ static errno_t hr_raid1_rebuild(void *arg) hr_volume_t *vol = arg; void *buf = NULL; size_t rebuild_idx; + hr_extent_t *rebuild_ext = NULL; errno_t rc; rc = init_rebuild(vol, &rebuild_idx); if (rc != EOK) return rc; + rebuild_ext = &vol->extents[rebuild_idx]; + size_t left = vol->data_blkno; size_t max_blks = DATA_XFER_LIMIT / vol->bsize; - buf = malloc(max_blks * vol->bsize); + buf = hr_malloc_waitok(max_blks * vol->bsize); size_t cnt; uint64_t ba = 0; hr_add_data_offset(vol, &ba); /* - * XXX: this is useless here after simplified DI, because - * rebuild cannot be triggered while ongoing rebuild + * this is not necessary because a rebuild is + * protected by itself, i.e. there can be only + * one REBUILD at a time */ fibril_rwlock_read_lock(&vol->extents_lock); @@ -485,15 +493,23 @@ static errno_t hr_raid1_rebuild(void *arg) cnt = min(max_blks, left); rl = hr_range_lock_acquire(vol, ba, cnt); - if (rl == NULL) { - rc = ENOMEM; - goto end; - } atomic_store_explicit(&vol->rebuild_blk, ba, memory_order_relaxed); - rc = hr_raid1_restore_blocks(vol, rebuild_idx, ba, cnt, buf); + rc = hr_raid1_bd_op(HR_BD_READ, vol, ba, cnt, buf, NULL, + cnt * vol->bsize); + if (rc != EOK) { + hr_range_lock_release(rl); + goto end; + } + + rc = hr_write_direct(rebuild_ext->svc_id, ba, cnt, buf); + if (rc != EOK) { + hr_raid1_ext_state_cb(vol, rebuild_idx, rc); + hr_range_lock_release(rl); + goto end; + } percent = ((ba + cnt) * 100) / vol->data_blkno; if (percent != old_percent) { @@ -504,9 +520,6 @@ static errno_t hr_raid1_rebuild(void *arg) hr_range_lock_release(rl); - if (rc != EOK) - goto end; - ba += cnt; left -= cnt; old_percent = percent; @@ -519,34 +532,13 @@ static errno_t hr_raid1_rebuild(void *arg) hr_update_ext_state(vol, rebuild_idx, HR_EXT_ONLINE); - /* - * We can be optimistic here, if some extents are - * still INVALID, FAULTY or MISSING, the update vol - * function will pick them up, and set the volume - * state accordingly. - */ - hr_update_vol_state(vol, HR_VOL_OPTIMAL); hr_mark_vol_state_dirty(vol); fibril_rwlock_write_unlock(&vol->states_lock); - (void)vol->meta_ops->save(vol, WITH_STATE_CALLBACK); + /* (void)vol->meta_ops->save(vol, WITH_STATE_CALLBACK); */ end: - if (rc != EOK) { - /* - * We can fail either because: - * - the rebuild extent failing or invalidation - * - there is are no ONLINE extents (vol is FAULTY) - * - we got ENOMEM on all READs (we also invalidate the - * rebuild extent here, for now) - */ - fibril_rwlock_write_lock(&vol->states_lock); - hr_update_vol_state(vol, HR_VOL_DEGRADED); - hr_mark_vol_state_dirty(vol); - fibril_rwlock_write_unlock(&vol->states_lock); - } - fibril_rwlock_read_unlock(&vol->extents_lock); hr_raid1_vol_state_eval(vol); @@ -565,14 +557,6 @@ static errno_t init_rebuild(hr_volume_t *vol, size_t *rebuild_idx) fibril_rwlock_write_lock(&vol->states_lock); fibril_mutex_lock(&vol->hotspare_lock); - /* XXX: allow REBUILD on INVALID extents */ - if (vol->hotspare_no == 0) { - HR_WARN("hr_raid1_rebuild(): no free hotspares on \"%s\", " - "aborting rebuild\n", vol->devname); - rc = EINVAL; - goto error; - } - size_t bad = vol->extent_no; for (size_t i = 0; i < vol->extent_no; i++) { if (vol->extents[i].state != HR_EXT_ONLINE) { @@ -581,28 +565,46 @@ static errno_t init_rebuild(hr_volume_t *vol, size_t *rebuild_idx) } } - if (bad == vol->extent_no) { - HR_WARN("hr_raid1_rebuild(): no bad extent on \"%s\", " - "aborting rebuild\n", vol->devname); + if (bad == vol->extent_no) rc = EINVAL; - goto error; + else if (vol->state != HR_VOL_DEGRADED) + rc = EINVAL; + + size_t invalid = vol->extent_no; + for (size_t i = 0; i < vol->extent_no; i++) { + if (vol->extents[i].state == HR_EXT_INVALID) { + invalid = i; + break; + } } - size_t hotspare_idx = vol->hotspare_no - 1; + if (invalid < vol->extent_no) + bad = invalid; - hr_ext_state_t hs_state = vol->hotspares[hotspare_idx].state; - if (hs_state != HR_EXT_HOTSPARE) { - HR_ERROR("hr_raid1_rebuild(): invalid hotspare state \"%s\", " - "aborting rebuild\n", hr_get_ext_state_str(hs_state)); + if (bad != invalid && vol->hotspare_no == 0) rc = EINVAL; - goto error; - } - rc = swap_hs(vol, bad, hotspare_idx); - if (rc != EOK) { - HR_ERROR("hr_raid1_rebuild(): swapping hotspare failed, " - "aborting rebuild\n"); + if (rc != EOK) goto error; + + if (bad != invalid) { + size_t hotspare_idx = vol->hotspare_no - 1; + + hr_ext_state_t hs_state = vol->hotspares[hotspare_idx].state; + if (hs_state != HR_EXT_HOTSPARE) { + HR_ERROR("hr_raid1_rebuild(): invalid hotspare" + "state \"%s\", aborting rebuild\n", + hr_get_ext_state_str(hs_state)); + rc = EINVAL; + goto error; + } + + rc = swap_hs(vol, bad, hotspare_idx); + if (rc != EOK) { + HR_ERROR("hr_raid1_rebuild(): swapping " + "hotspare failed, aborting rebuild\n"); + goto error; + } } hr_extent_t *rebuild_ext = &vol->extents[bad]; @@ -626,7 +628,7 @@ static errno_t init_rebuild(hr_volume_t *vol, size_t *rebuild_idx) static errno_t swap_hs(hr_volume_t *vol, size_t bad, size_t hs) { - HR_DEBUG("hr_raid1_rebuild(): swapping in hotspare\n"); + HR_DEBUG("%s()", __func__); service_id_t faulty_svc_id = vol->extents[bad].svc_id; service_id_t hs_svc_id = vol->hotspares[hs].svc_id; @@ -645,79 +647,5 @@ static errno_t swap_hs(hr_volume_t *vol, size_t bad, size_t hs) return EOK; } -static errno_t hr_raid1_restore_blocks(hr_volume_t *vol, size_t rebuild_idx, - uint64_t ba, size_t cnt, void *buf) -{ - assert(fibril_rwlock_is_locked(&vol->extents_lock)); - - errno_t rc = ENOENT; - hr_extent_t *ext, *rebuild_ext = &vol->extents[rebuild_idx]; - - fibril_rwlock_read_lock(&vol->states_lock); - hr_ext_state_t rebuild_ext_state = rebuild_ext->state; - fibril_rwlock_read_unlock(&vol->states_lock); - - if (rebuild_ext_state != HR_EXT_REBUILD) - return EINVAL; - - for (size_t i = 0; i < vol->extent_no; i++) { - fibril_rwlock_read_lock(&vol->states_lock); - ext = &vol->extents[i]; - if (ext->state != HR_EXT_ONLINE) { - fibril_rwlock_read_unlock(&vol->states_lock); - continue; - } - fibril_rwlock_read_unlock(&vol->states_lock); - - rc = block_read_direct(ext->svc_id, ba, cnt, buf); - if (rc == EOK) - break; - - if (rc != ENOMEM) - hr_raid1_ext_state_cb(vol, i, rc); - - if (i + 1 >= vol->extent_no) { - if (rc != ENOMEM) { - HR_ERROR("rebuild on \"%s\" (%" PRIun "), " - "failed due to too many failed extents\n", - vol->devname, vol->svc_id); - } - - /* for now we have to invalidate the rebuild extent */ - if (rc == ENOMEM) { - HR_ERROR("rebuild on \"%s\" (%" PRIun "), " - "failed due to too many failed reads, " - "because of not enough memory\n", - vol->devname, vol->svc_id); - hr_raid1_ext_state_cb(vol, rebuild_idx, - ENOMEM); - } - - return rc; - } - } - - rc = block_write_direct(rebuild_ext->svc_id, ba, cnt, buf); - if (rc != EOK) { - /* - * Here we dont handle ENOMEM, because maybe in the - * future, there is going to be M_WAITOK, or we are - * going to wait for more memory, so that we don't - * have to invalidate it... - * - * XXX: for now we do - */ - hr_raid1_ext_state_cb(vol, rebuild_idx, rc); - - HR_ERROR("rebuild on \"%s\" (%" PRIun "), failed due to " - "the rebuilt extent no. %zu WRITE (rc: %s)\n", - vol->devname, vol->svc_id, rebuild_idx, str_error(rc)); - - return rc; - } - - return EOK; -} - /** @} */ From a5a2dcfd34fb6037537045182f88d5a711a0d072 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 23 Jun 2025 13:47:28 +0200 Subject: [PATCH 270/324] hr: util.c: make state changes logs mostly DEBUG level --- uspace/srv/bd/hr/util.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 7673fb1ef7..fbc4f77787 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -444,7 +444,7 @@ void hr_update_ext_state(hr_volume_t *vol, size_t ext_idx, hr_ext_state_t s) assert(ext_idx < vol->extent_no); hr_ext_state_t old = vol->extents[ext_idx].state; - HR_NOTE("\"%s\": changing extent %zu state: %s -> %s\n", + HR_DEBUG("\"%s\": changing extent %zu state: %s -> %s\n", vol->devname, ext_idx, hr_get_ext_state_str(old), hr_get_ext_state_str(s)); vol->extents[ext_idx].state = s; @@ -458,7 +458,7 @@ void hr_update_hotspare_state(hr_volume_t *vol, size_t hs_idx, assert(hs_idx < vol->hotspare_no); hr_ext_state_t old = vol->hotspares[hs_idx].state; - HR_NOTE("\"%s\": changing hotspare %zu state: %s -> %s\n", + HR_DEBUG("\"%s\": changing hotspare %zu state: %s -> %s\n", vol->devname, hs_idx, hr_get_ext_state_str(old), hr_get_ext_state_str(s)); vol->hotspares[hs_idx].state = s; @@ -468,7 +468,7 @@ void hr_update_vol_state(hr_volume_t *vol, hr_vol_state_t new) { assert(fibril_rwlock_is_write_locked(&vol->states_lock)); - HR_NOTE("\"%s\": changing volume state: %s -> %s\n", vol->devname, + HR_NOTE("\"%s\": volume state changed: %s -> %s\n", vol->devname, hr_get_vol_state_str(vol->state), hr_get_vol_state_str(new)); vol->state = new; } @@ -481,7 +481,7 @@ void hr_update_ext_svc_id(hr_volume_t *vol, size_t ext_idx, service_id_t new) assert(ext_idx < vol->extent_no); service_id_t old = vol->extents[ext_idx].svc_id; - HR_NOTE("\"%s\": changing extent no. %zu svc_id: (%" PRIun ") -> " + HR_DEBUG("\"%s\": changing extent no. %zu svc_id: (%" PRIun ") -> " "(%" PRIun ")\n", vol->devname, ext_idx, old, new); vol->extents[ext_idx].svc_id = new; } @@ -494,7 +494,7 @@ void hr_update_hotspare_svc_id(hr_volume_t *vol, size_t hs_idx, assert(hs_idx < vol->hotspare_no); service_id_t old = vol->hotspares[hs_idx].svc_id; - HR_NOTE("\"%s\": changing hotspare no. %zu svc_id: (%" PRIun ") -> " + HR_DEBUG("\"%s\": changing hotspare no. %zu svc_id: (%" PRIun ") -> " "(%" PRIun ")\n", vol->devname, hs_idx, old, new); vol->hotspares[hs_idx].svc_id = new; } From f6590c438a05eef50987733a9f05063ef031c2f8 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 23 Jun 2025 15:28:37 +0200 Subject: [PATCH 271/324] hr: io.c: fix typo in reconstruct reader --- uspace/srv/bd/hr/io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uspace/srv/bd/hr/io.c b/uspace/srv/bd/hr/io.c index 7ac23645ce..ec06076ace 100644 --- a/uspace/srv/bd/hr/io.c +++ b/uspace/srv/bd/hr/io.c @@ -281,7 +281,7 @@ errno_t hr_io_raid5_reconstruct_reader(void *arg) uint8_t *data = hr_malloc_waitok(io->cnt * io->vol->bsize); - rc = hr_write_direct(extents[ext_idx].svc_id, io->ba, io->cnt, data); + 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); From 09c195e8b9cf55320cf91b7cc57d99fd9542e356 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 23 Jun 2025 15:32:13 +0200 Subject: [PATCH 272/324] hr: move rebuild init to util.c --- uspace/srv/bd/hr/raid1.c | 102 +-------------------------------------- uspace/srv/bd/hr/util.c | 102 +++++++++++++++++++++++++++++++++++++++ uspace/srv/bd/hr/util.h | 1 + 3 files changed, 104 insertions(+), 101 deletions(-) diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 50e2e95d76..98ed43cf1e 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -61,8 +61,6 @@ static size_t hr_raid1_count_good_extents(hr_volume_t *, uint64_t, size_t, static errno_t hr_raid1_bd_op(hr_bd_op_type_t, hr_volume_t *, aoff64_t, size_t, void *, const void *, size_t); static errno_t hr_raid1_rebuild(void *); -static errno_t init_rebuild(hr_volume_t *, size_t *); -static errno_t swap_hs(hr_volume_t *, size_t, size_t); /* bdops */ static errno_t hr_raid1_bd_open(bd_srvs_t *, bd_srv_t *); @@ -458,7 +456,7 @@ static errno_t hr_raid1_rebuild(void *arg) hr_extent_t *rebuild_ext = NULL; errno_t rc; - rc = init_rebuild(vol, &rebuild_idx); + rc = hr_init_rebuild(vol, &rebuild_idx); if (rc != EOK) return rc; @@ -549,103 +547,5 @@ static errno_t hr_raid1_rebuild(void *arg) return rc; } -static errno_t init_rebuild(hr_volume_t *vol, size_t *rebuild_idx) -{ - errno_t rc = EOK; - - fibril_rwlock_write_lock(&vol->extents_lock); - fibril_rwlock_write_lock(&vol->states_lock); - fibril_mutex_lock(&vol->hotspare_lock); - - size_t bad = vol->extent_no; - for (size_t i = 0; i < vol->extent_no; i++) { - if (vol->extents[i].state != HR_EXT_ONLINE) { - bad = i; - break; - } - } - - if (bad == vol->extent_no) - rc = EINVAL; - else if (vol->state != HR_VOL_DEGRADED) - rc = EINVAL; - - size_t invalid = vol->extent_no; - for (size_t i = 0; i < vol->extent_no; i++) { - if (vol->extents[i].state == HR_EXT_INVALID) { - invalid = i; - break; - } - } - - if (invalid < vol->extent_no) - bad = invalid; - - if (bad != invalid && vol->hotspare_no == 0) - rc = EINVAL; - - if (rc != EOK) - goto error; - - if (bad != invalid) { - size_t hotspare_idx = vol->hotspare_no - 1; - - hr_ext_state_t hs_state = vol->hotspares[hotspare_idx].state; - if (hs_state != HR_EXT_HOTSPARE) { - HR_ERROR("hr_raid1_rebuild(): invalid hotspare" - "state \"%s\", aborting rebuild\n", - hr_get_ext_state_str(hs_state)); - rc = EINVAL; - goto error; - } - - rc = swap_hs(vol, bad, hotspare_idx); - if (rc != EOK) { - HR_ERROR("hr_raid1_rebuild(): swapping " - "hotspare failed, aborting rebuild\n"); - goto error; - } - } - - hr_extent_t *rebuild_ext = &vol->extents[bad]; - - HR_DEBUG("hr_raid1_rebuild(): starting REBUILD on extent no. %zu " - "(%" PRIun ")\n", bad, rebuild_ext->svc_id); - - atomic_store_explicit(&vol->rebuild_blk, 0, memory_order_relaxed); - - hr_update_ext_state(vol, bad, HR_EXT_REBUILD); - hr_update_vol_state(vol, HR_VOL_REBUILD); - - *rebuild_idx = bad; -error: - fibril_mutex_unlock(&vol->hotspare_lock); - fibril_rwlock_write_unlock(&vol->states_lock); - fibril_rwlock_write_unlock(&vol->extents_lock); - - return rc; -} - -static errno_t swap_hs(hr_volume_t *vol, size_t bad, size_t hs) -{ - HR_DEBUG("%s()", __func__); - - service_id_t faulty_svc_id = vol->extents[bad].svc_id; - service_id_t hs_svc_id = vol->hotspares[hs].svc_id; - - hr_update_ext_svc_id(vol, bad, hs_svc_id); - hr_update_ext_state(vol, bad, HR_EXT_HOTSPARE); - - hr_update_hotspare_svc_id(vol, hs, 0); - hr_update_hotspare_state(vol, hs, HR_EXT_MISSING); - - vol->hotspare_no--; - - if (faulty_svc_id != 0) - block_fini(faulty_svc_id); - - return EOK; -} - /** @} */ diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index fbc4f77787..a37b09ed74 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -68,6 +68,7 @@ static errno_t hr_util_get_matching_md_svcs_list(list_t *, list_t *, static errno_t hr_util_assemble_from_matching_list(list_t *, hr_metadata_type_t); static errno_t hr_fill_svcs_list_from_cfg(hr_config_t *, list_t *); +static errno_t hr_swap_hs(hr_volume_t *, size_t, size_t); #define HR_RL_LIST_LOCK(vol) (fibril_mutex_lock(&(vol)->range_lock_list_lock)) #define HR_RL_LIST_UNLOCK(vol) \ @@ -1127,5 +1128,106 @@ errno_t hr_sync_extents(hr_volume_t *vol) return rc; } +errno_t hr_init_rebuild(hr_volume_t *vol, size_t *rebuild_idx) +{ + errno_t rc = EOK; + + if (vol->level == HR_LVL_0) + return EINVAL; + + fibril_rwlock_write_lock(&vol->extents_lock); + fibril_rwlock_write_lock(&vol->states_lock); + fibril_mutex_lock(&vol->hotspare_lock); + + size_t bad = vol->extent_no; + for (size_t i = 0; i < vol->extent_no; i++) { + if (vol->extents[i].state != HR_EXT_ONLINE) { + bad = i; + break; + } + } + + if (bad == vol->extent_no) + rc = EINVAL; + else if (vol->state != HR_VOL_DEGRADED) + rc = EINVAL; + + size_t invalid = vol->extent_no; + for (size_t i = 0; i < vol->extent_no; i++) { + if (vol->extents[i].state == HR_EXT_INVALID) { + invalid = i; + break; + } + } + + if (invalid < vol->extent_no) + bad = invalid; + + if (bad != invalid && vol->hotspare_no == 0) + rc = EINVAL; + + if (rc != EOK) + goto error; + + if (bad != invalid) { + size_t hotspare_idx = vol->hotspare_no - 1; + + hr_ext_state_t hs_state = vol->hotspares[hotspare_idx].state; + if (hs_state != HR_EXT_HOTSPARE) { + HR_ERROR("hr_raid1_rebuild(): invalid hotspare" + "state \"%s\", aborting rebuild\n", + hr_get_ext_state_str(hs_state)); + rc = EINVAL; + goto error; + } + + rc = hr_swap_hs(vol, bad, hotspare_idx); + if (rc != EOK) { + HR_ERROR("hr_raid1_rebuild(): swapping " + "hotspare failed, aborting rebuild\n"); + goto error; + } + } + + hr_extent_t *rebuild_ext = &vol->extents[bad]; + + HR_DEBUG("hr_raid1_rebuild(): starting REBUILD on extent no. %zu " + "(%" PRIun ")\n", bad, rebuild_ext->svc_id); + + atomic_store_explicit(&vol->rebuild_blk, 0, memory_order_relaxed); + + hr_update_ext_state(vol, bad, HR_EXT_REBUILD); + hr_update_vol_state(vol, HR_VOL_REBUILD); + + *rebuild_idx = bad; +error: + fibril_mutex_unlock(&vol->hotspare_lock); + fibril_rwlock_write_unlock(&vol->states_lock); + fibril_rwlock_write_unlock(&vol->extents_lock); + + return rc; +} + +static errno_t hr_swap_hs(hr_volume_t *vol, size_t bad, size_t hs) +{ + HR_DEBUG("%s()", __func__); + + service_id_t faulty_svc_id = vol->extents[bad].svc_id; + service_id_t hs_svc_id = vol->hotspares[hs].svc_id; + + hr_update_ext_svc_id(vol, bad, hs_svc_id); + hr_update_ext_state(vol, bad, HR_EXT_HOTSPARE); + + hr_update_hotspare_svc_id(vol, hs, 0); + hr_update_hotspare_state(vol, hs, HR_EXT_MISSING); + + vol->hotspare_no--; + + if (faulty_svc_id != 0) + block_fini(faulty_svc_id); + + return EOK; +} + /** @} */ diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index fbacda45fe..384da81194 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -111,6 +111,7 @@ extern errno_t hr_util_try_assemble(hr_config_t *, size_t *); extern errno_t hr_util_add_hotspare(hr_volume_t *, service_id_t); extern void hr_raid5_xor(void *, const void *, size_t); extern errno_t hr_sync_extents(hr_volume_t *); +extern errno_t hr_init_rebuild(hr_volume_t *, size_t *); #endif From cdfcaeaeb03f76e707b13352d32fd0ff986958e1 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 23 Jun 2025 15:39:56 +0200 Subject: [PATCH 273/324] hr: RAID 5 rebuild --- uspace/srv/bd/hr/io.c | 2 +- uspace/srv/bd/hr/parity_stripe.c | 48 +++--- uspace/srv/bd/hr/parity_stripe.h | 4 +- uspace/srv/bd/hr/raid5.c | 254 +++++++++++++------------------ uspace/srv/bd/hr/util.c | 15 -- uspace/srv/bd/hr/util.h | 2 - 6 files changed, 130 insertions(+), 195 deletions(-) diff --git a/uspace/srv/bd/hr/io.c b/uspace/srv/bd/hr/io.c index ec06076ace..220d0edc63 100644 --- a/uspace/srv/bd/hr/io.c +++ b/uspace/srv/bd/hr/io.c @@ -314,7 +314,7 @@ errno_t hr_io_raid5_parity_writer(void *arg) 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, stripe->p_extent, rc); + io->vol->hr_ops.ext_state_cb(io->vol, io->extent, rc); return rc; } diff --git a/uspace/srv/bd/hr/parity_stripe.c b/uspace/srv/bd/hr/parity_stripe.c index 38ea5e8221..58340520bf 100644 --- a/uspace/srv/bd/hr/parity_stripe.c +++ b/uspace/srv/bd/hr/parity_stripe.c @@ -52,34 +52,26 @@ static void execute_stripe_degraded_good(hr_stripe_t *, size_t); static bool hr_stripe_range_non_extension(const range_t *, const range_t *, range_t *); static size_t hr_stripe_merge_extent_spans(hr_stripe_t *, size_t, range_t [2]); -static void hr_reset_stripe(hr_stripe_t *); static void hr_stripe_extend_range(range_t *, const range_t *); static bool hr_ranges_overlap(const range_t *, const range_t *, range_t *); -hr_stripe_t *hr_create_stripes(hr_volume_t *vol, size_t cnt, bool write) +hr_stripe_t *hr_create_stripes(hr_volume_t *vol, uint64_t strip_size, + size_t cnt, bool write) { - hr_stripe_t *stripes = calloc(cnt, sizeof(*stripes)); - if (stripes == NULL) - return NULL; + hr_stripe_t *stripes = hr_calloc_waitok(cnt, sizeof(*stripes)); for (size_t i = 0; i < cnt; i++) { fibril_mutex_initialize(&stripes[i].parity_lock); fibril_condvar_initialize(&stripes[i].ps_added_cv); stripes[i].vol = vol; stripes[i].write = write; - stripes[i].parity = calloc(1, vol->strip_size); - if (stripes[i].parity == NULL) - goto error; - stripes[i].extent_span = - calloc(vol->extent_no, sizeof(*stripes[i].extent_span)); - if (stripes[i].extent_span == NULL) - goto error; + stripes[i].parity = hr_calloc_waitok(1, strip_size); + stripes[i].parity_size = strip_size; + stripes[i].extent_span = hr_calloc_waitok(vol->extent_no, + sizeof(*stripes[i].extent_span)); } return stripes; -error: - hr_destroy_stripes(stripes, cnt); - return NULL; } void hr_destroy_stripes(hr_stripe_t *stripes, size_t cnt) @@ -97,6 +89,18 @@ void hr_destroy_stripes(hr_stripe_t *stripes, size_t cnt) free(stripes); } +void hr_reset_stripe(hr_stripe_t *stripe) +{ + memset(stripe->parity, 0, stripe->parity_size); + stripe->ps_added = 0; + stripe->ps_to_be_added = 0; + stripe->p_count_final = false; + + stripe->rc = EOK; + stripe->abort = false; + stripe->done = false; +} + void hr_stripe_commit_parity(hr_stripe_t *stripe, uint64_t strip_off, const void *data, uint64_t size) { @@ -877,20 +881,6 @@ static size_t hr_stripe_merge_extent_spans(hr_stripe_t *s, size_t extent_no, return out_count; } -static void hr_reset_stripe(hr_stripe_t *stripe) -{ - printf("%s\n", __func__); - - memset(stripe->parity, 0, stripe->vol->strip_size); - stripe->ps_added = 0; - stripe->ps_to_be_added = 0; - stripe->p_count_final = false; - - stripe->rc = EOK; - stripe->abort = false; - stripe->done = false; -} - /** Extend a range. * * @param r1 Output range. diff --git a/uspace/srv/bd/hr/parity_stripe.h b/uspace/srv/bd/hr/parity_stripe.h index 99867aa0c3..655b08d5bc 100644 --- a/uspace/srv/bd/hr/parity_stripe.h +++ b/uspace/srv/bd/hr/parity_stripe.h @@ -72,6 +72,7 @@ typedef struct hr_stripe { fibril_mutex_t parity_lock; uint8_t *parity; /* the actual parity strip */ + uint64_t parity_size; /* parity writers waiting until this many parity commits */ size_t ps_to_be_added; @@ -103,8 +104,9 @@ typedef struct hr_stripe { size_t range_count; } hr_stripe_t; -extern hr_stripe_t *hr_create_stripes(hr_volume_t *, size_t, bool); +extern hr_stripe_t *hr_create_stripes(hr_volume_t *, uint64_t, size_t, bool); extern void hr_destroy_stripes(hr_stripe_t *, size_t); +extern void hr_reset_stripe(hr_stripe_t *); extern void hr_stripe_commit_parity(hr_stripe_t *, uint64_t, const void *, uint64_t); extern void hr_stripe_wait_for_parity_commits(hr_stripe_t *); diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index d2dc17bdc9..7d8d5d8381 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -56,12 +56,10 @@ #include "var.h" static void hr_raid5_vol_state_eval_forced(hr_volume_t *); - static size_t hr_raid5_parity_extent(hr_level_t, hr_layout_t, size_t, uint64_t); static size_t hr_raid5_data_extent(hr_level_t, hr_layout_t, size_t, uint64_t, uint64_t); - static errno_t hr_raid5_rebuild(void *); /* bdops */ @@ -250,18 +248,10 @@ static errno_t hr_raid5_bd_read_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt, uint64_t end_stripe = end_strip_no / (vol->extent_no - 1); size_t stripes_cnt = end_stripe - start_stripe + 1; - hr_stripe_t *stripes = hr_create_stripes(vol, stripes_cnt, false); - if (stripes == NULL) - return ENOMEM; + hr_stripe_t *stripes = hr_create_stripes(vol, vol->strip_size, + stripes_cnt, false); - /* - * Pre-allocate range locks, because after group creation and - * firing off IO requests there is no easy consistent ENOMEM error - * path. - */ hr_range_lock_t **rlps = hr_malloc_waitok(stripes_cnt * sizeof(*rlps)); - for (size_t i = 0; i < stripes_cnt; i++) - rlps[i] = hr_malloc_waitok(sizeof(**rlps)); /* * extent order has to be locked for the whole IO duration, @@ -271,7 +261,7 @@ static errno_t hr_raid5_bd_read_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt, for (uint64_t s = start_stripe; s <= end_stripe; s++) { uint64_t relative = s - start_stripe; - hr_range_lock_acquire_noalloc(rlps[relative], vol, s, 1); + rlps[relative] = hr_range_lock_acquire(vol, s, 1); } uint64_t phys_block, len; @@ -377,6 +367,8 @@ static errno_t hr_raid5_bd_read_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt, for (size_t i = 0; i < stripes_cnt; i++) hr_range_lock_release(rlps[i]); + free(rlps); + hr_destroy_stripes(stripes, stripes_cnt); return rc; @@ -419,9 +411,8 @@ static errno_t hr_raid5_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, uint64_t end_stripe = end_strip_no / (vol->extent_no - 1); size_t stripes_cnt = end_stripe - start_stripe + 1; - hr_stripe_t *stripes = hr_create_stripes(vol, stripes_cnt, true); - if (stripes == NULL) - return ENOMEM; + hr_stripe_t *stripes = hr_create_stripes(vol, vol->strip_size, + stripes_cnt, true); uint64_t stripe_size = strip_size * (vol->extent_no - 1); @@ -468,14 +459,7 @@ static errno_t hr_raid5_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, stripes[relative_stripe].subtract = true; } - /* - * Pre-allocate range locks, because after group creation and - * firing off IO requests there is no easy consistent ENOMEM error - * path. - */ hr_range_lock_t **rlps = hr_malloc_waitok(stripes_cnt * sizeof(*rlps)); - for (size_t i = 0; i < stripes_cnt; i++) - rlps[i] = hr_malloc_waitok(sizeof(**rlps)); /* * extent order has to be locked for the whole IO duration, @@ -485,7 +469,7 @@ static errno_t hr_raid5_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, for (uint64_t s = start_stripe; s <= end_stripe; s++) { uint64_t relative = s - start_stripe; - hr_range_lock_acquire_noalloc(rlps[relative], vol, s, 1); + rlps[relative] = hr_range_lock_acquire(vol, s, 1); } uint64_t phys_block, len; @@ -589,6 +573,8 @@ static errno_t hr_raid5_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, for (size_t i = 0; i < stripes_cnt; i++) hr_range_lock_release(rlps[i]); + free(rlps); + hr_destroy_stripes(stripes, stripes_cnt); return rc; @@ -622,6 +608,12 @@ static void hr_raid5_vol_state_eval_forced(hr_volume_t *vol) if (vol->extents[i].state != HR_EXT_ONLINE) bad++; + size_t invalid_no = hr_count_extents(vol, HR_EXT_INVALID); + + fibril_mutex_lock(&vol->hotspare_lock); + size_t hs_no = vol->hotspare_no; + fibril_mutex_unlock(&vol->hotspare_lock); + switch (bad) { case 0: if (state != HR_VOL_OPTIMAL) @@ -632,11 +624,7 @@ static void hr_raid5_vol_state_eval_forced(hr_volume_t *vol) hr_update_vol_state(vol, HR_VOL_DEGRADED); if (state != HR_VOL_REBUILD) { - /* XXX: allow REBUILD on INVALID extents */ - fibril_mutex_lock(&vol->hotspare_lock); - size_t hs_no = vol->hotspare_no; - fibril_mutex_unlock(&vol->hotspare_lock); - if (hs_no > 0) { + if (hs_no > 0 || invalid_no > 0) { fid_t fib = fibril_create(hr_raid5_rebuild, vol); if (fib == 0) @@ -656,16 +644,6 @@ static void hr_raid5_vol_state_eval_forced(hr_volume_t *vol) fibril_rwlock_read_unlock(&vol->extents_lock); } -static void xor(void *dst, const void *src, size_t size) -{ - size_t i; - uint64_t *d = dst; - const uint64_t *s = src; - - for (i = 0; i < size / sizeof(uint64_t); ++i) - *d++ ^= *s++; -} - static size_t hr_raid5_parity_extent(hr_level_t level, hr_layout_t layout, size_t extent_no, uint64_t strip_no) { @@ -729,119 +707,111 @@ static size_t hr_raid5_data_extent(hr_level_t level, static errno_t hr_raid5_rebuild(void *arg) { - HR_DEBUG("hr_raid5_rebuild()\n"); + HR_DEBUG("%s()", __func__); hr_volume_t *vol = arg; errno_t rc = EOK; + size_t rebuild_idx; void *buf = NULL, *xorbuf = NULL; - fibril_rwlock_read_lock(&vol->extents_lock); - fibril_rwlock_write_lock(&vol->states_lock); + rc = hr_init_rebuild(vol, &rebuild_idx); + if (rc != EOK) + return rc; - if (vol->hotspare_no == 0) { - HR_WARN("hr_raid5_rebuild(): no free hotspares on \"%s\", " - "aborting rebuild\n", vol->devname); - /* retval isn't checked for now */ - goto end; - } + uint64_t max_blks = DATA_XFER_LIMIT / vol->bsize; + uint64_t left = vol->data_blkno / (vol->extent_no - 1); + buf = hr_malloc_waitok(max_blks * vol->bsize); + xorbuf = hr_malloc_waitok(max_blks * vol->bsize); - size_t bad = vol->extent_no; - for (size_t i = 0; i < vol->extent_no; i++) { - if (vol->extents[i].state == HR_EXT_FAILED) { - bad = i; - break; - } - } + uint64_t strip_size = vol->strip_size / vol->bsize; /* in blocks */ - if (bad == vol->extent_no) { - HR_WARN("hr_raid5_rebuild(): no bad extent on \"%s\", " - "aborting rebuild\n", vol->devname); - /* retval isn't checked for now */ - goto end; - } + uint64_t ba = 0, cnt; + hr_add_data_offset(vol, &ba); - size_t hotspare_idx = vol->hotspare_no - 1; + /* + * this is not necessary because a rebuild is + * protected by itself, i.e. there can be only + * one REBUILD at a time + */ + fibril_rwlock_read_lock(&vol->extents_lock); - hr_ext_state_t hs_state = vol->hotspares[hotspare_idx].state; - if (hs_state != HR_EXT_HOTSPARE) { - HR_ERROR("hr_raid5_rebuild(): invalid hotspare state \"%s\", " - "aborting rebuild\n", hr_get_ext_state_str(hs_state)); - rc = EINVAL; - goto end; + /* increment metadata counter only on first write */ + bool exp = false; + if (atomic_compare_exchange_strong(&vol->first_write, &exp, true)) { + vol->meta_ops->inc_counter(vol); + vol->meta_ops->save(vol, WITH_STATE_CALLBACK); } - HR_DEBUG("hr_raid5_rebuild(): swapping in hotspare\n"); - - block_fini(vol->extents[bad].svc_id); - - vol->extents[bad].svc_id = vol->hotspares[hotspare_idx].svc_id; - hr_update_ext_state(vol, bad, HR_EXT_HOTSPARE); + hr_range_lock_t *rl = NULL; + hr_stripe_t *stripe = hr_create_stripes(vol, max_blks * vol->bsize, 1, + false); - vol->hotspares[hotspare_idx].svc_id = 0; - fibril_mutex_lock(&vol->hotspare_lock); - hr_update_hotspare_state(vol, hotspare_idx, HR_EXT_MISSING); - fibril_mutex_unlock(&vol->hotspare_lock); - - vol->hotspare_no--; - - hr_extent_t *rebuild_ext = &vol->extents[bad]; + unsigned int percent, old_percent = 100; + while (left != 0) { + cnt = min(left, max_blks); - HR_DEBUG("hr_raid5_rebuild(): starting rebuild on (%" PRIun ")\n", - rebuild_ext->svc_id); + uint64_t strip_no = ba / strip_size; + uint64_t last_ba = ba + cnt - 1; + uint64_t end_strip_no = last_ba / strip_size; + uint64_t start_stripe = strip_no / (vol->extent_no - 1); + uint64_t end_stripe = end_strip_no / (vol->extent_no - 1); + size_t stripes_cnt = end_stripe - start_stripe + 1; - hr_update_ext_state(vol, bad, HR_EXT_REBUILD); - hr_update_vol_state(vol, HR_VOL_REBUILD); + stripe->ps_to_be_added = vol->extent_no - 1; + stripe->p_count_final = true; - uint64_t max_blks = DATA_XFER_LIMIT / vol->bsize; - uint64_t left = vol->data_blkno / (vol->extent_no - 1); - buf = malloc(max_blks * vol->bsize); - xorbuf = malloc(max_blks * vol->bsize); + hr_fgroup_t *worker_group = + hr_fgroup_create(vol->fge, vol->extent_no); - uint64_t ba = 0, cnt; - hr_add_data_offset(vol, &ba); + rl = hr_range_lock_acquire(vol, start_stripe, stripes_cnt); - while (left != 0) { - cnt = min(left, max_blks); + atomic_store_explicit(&vol->rebuild_blk, ba, + memory_order_relaxed); - /* - * Almost the same as read_degraded, - * but we don't want to allocate new - * xorbuf each blk rebuild batch. - */ - bool first = true; - for (size_t i = 0; i < vol->extent_no; i++) { - if (i == bad) + for (size_t e = 0; e < vol->extent_no; e++) { + if (e == rebuild_idx) continue; - if (first) - rc = block_read_direct(vol->extents[i].svc_id, - ba, cnt, xorbuf); - else - rc = block_read_direct(vol->extents[i].svc_id, - ba, cnt, buf); - if (rc != EOK) { - hr_raid5_ext_state_cb(vol, i, rc); - HR_ERROR("rebuild on \"%s\" (%" PRIun "), " - "failed due to a failed ONLINE extent, " - "number %zu\n", - vol->devname, vol->svc_id, i); - goto end; - } - if (!first) - xor(xorbuf, buf, cnt * vol->bsize); - else - first = false; + hr_io_raid5_t *io = hr_fgroup_alloc(worker_group); + io->extent = e; + io->ba = ba; + io->cnt = cnt; + io->strip_off = 0; + io->vol = vol; + io->stripe = stripe; + + hr_fgroup_submit(worker_group, + hr_io_raid5_reconstruct_reader, io); } - rc = block_write_direct(rebuild_ext->svc_id, ba, cnt, xorbuf); - if (rc != EOK) { - hr_raid5_ext_state_cb(vol, bad, rc); - HR_ERROR("rebuild on \"%s\" (%" PRIun "), failed due to " - "the rebuilt extent number %zu failing\n", - vol->devname, vol->svc_id, bad); + hr_io_raid5_t *io = hr_fgroup_alloc(worker_group); + io->extent = rebuild_idx; + io->ba = ba; + io->cnt = cnt; + io->strip_off = 0; + io->vol = vol; + io->stripe = stripe; + + hr_fgroup_submit(worker_group, hr_io_raid5_parity_writer, io); + + size_t failed; + (void)hr_fgroup_wait(worker_group, NULL, &failed); + if (failed > 0) { + hr_range_lock_release(rl); + HR_NOTE("\"%s\": REBUILD aborted.\n", vol->devname); goto end; } + percent = ((ba + cnt) * 100) / vol->data_blkno; + if (percent != old_percent) { + if (percent % 5 == 0) + HR_DEBUG("\"%s\" REBUILD progress: %u%%\n", + vol->devname, percent); + } + + hr_range_lock_release(rl); + hr_reset_stripe(stripe); + ba += cnt; left -= cnt; @@ -849,39 +819,29 @@ static errno_t hr_raid5_rebuild(void *arg) * Let other IO requests be served * during rebuild. */ - - /* - * fibril_rwlock_write_unlock(&vol->states_lock); - * fibril_mutex_unlock(&vol->lock); - * fibril_mutex_lock(&vol->lock); - * fibril_rwlock_write_lock(&vol->states_lock); - */ } HR_DEBUG("hr_raid5_rebuild(): rebuild finished on \"%s\" (%" PRIun "), " - "extent number %zu\n", vol->devname, vol->svc_id, hotspare_idx); + "extent number %zu\n", vol->devname, vol->svc_id, rebuild_idx); + + fibril_rwlock_write_lock(&vol->states_lock); - hr_update_ext_state(vol, bad, HR_EXT_ONLINE); + hr_update_ext_state(vol, rebuild_idx, HR_EXT_ONLINE); - fibril_rwlock_write_unlock(&vol->states_lock); - fibril_rwlock_read_unlock(&vol->extents_lock); + hr_mark_vol_state_dirty(vol); - rc = vol->meta_ops->save(vol, WITH_STATE_CALLBACK); + fibril_rwlock_write_unlock(&vol->states_lock); - fibril_rwlock_read_lock(&vol->extents_lock); - fibril_rwlock_write_lock(&vol->states_lock); + /* (void)vol->meta_ops->save(vol, WITH_STATE_CALLBACK); */ end: - hr_raid5_vol_state_eval_forced(vol); - - fibril_rwlock_write_unlock(&vol->states_lock); fibril_rwlock_read_unlock(&vol->extents_lock); - if (buf != NULL) - free(buf); + hr_raid1_vol_state_eval(vol); - if (xorbuf != NULL) - free(xorbuf); + hr_destroy_stripes(stripe, 1); + free(buf); + free(xorbuf); return rc; } diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index a37b09ed74..5fbe4cff24 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -54,8 +54,6 @@ #include "util.h" #include "var.h" -static hr_range_lock_t *hr_range_lock_acquire_internal(hr_range_lock_t *, - hr_volume_t *, uint64_t, uint64_t); static bool hr_range_lock_overlap(hr_range_lock_t *, hr_range_lock_t *); static errno_t hr_add_svc_linked_to_list(list_t *, service_id_t, bool, void *); static void free_dev_list_member(struct dev_list_member *); @@ -514,24 +512,11 @@ size_t hr_count_extents(hr_volume_t *vol, hr_ext_state_t state) return count; } -void hr_range_lock_acquire_noalloc(hr_range_lock_t *rl, hr_volume_t *vol, - uint64_t ba, uint64_t cnt) -{ - assert(rl != NULL); - (void)hr_range_lock_acquire_internal(rl, vol, ba, cnt); -} - hr_range_lock_t *hr_range_lock_acquire(hr_volume_t *vol, uint64_t ba, uint64_t cnt) { hr_range_lock_t *rl = hr_malloc_waitok(sizeof(hr_range_lock_t)); - return hr_range_lock_acquire_internal(rl, vol, ba, cnt); -} - -static hr_range_lock_t *hr_range_lock_acquire_internal(hr_range_lock_t *rl, - hr_volume_t *vol, uint64_t ba, uint64_t cnt) -{ rl->vol = vol; rl->off = ba; rl->len = cnt; diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index 384da81194..7ea9b89653 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -102,8 +102,6 @@ extern void hr_update_hotspare_svc_id(hr_volume_t *, size_t, service_id_t); extern void hr_sync_all_extents(hr_volume_t *); extern size_t hr_count_extents(hr_volume_t *, hr_ext_state_t); extern void hr_mark_vol_state_dirty(hr_volume_t *); -extern void hr_range_lock_acquire_noalloc(hr_range_lock_t *, hr_volume_t *, - uint64_t, uint64_t); extern hr_range_lock_t *hr_range_lock_acquire(hr_volume_t *, uint64_t, uint64_t); extern void hr_range_lock_release(hr_range_lock_t *); From f18e36e2bbc50b38693ef734c8811bf0cdf01584 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 23 Jun 2025 18:35:14 +0200 Subject: [PATCH 274/324] hr: metadata/native: make save use waitok allocation --- uspace/srv/bd/hr/metadata/native.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/uspace/srv/bd/hr/metadata/native.c b/uspace/srv/bd/hr/metadata/native.c index 1078a52db2..9bf083dc51 100644 --- a/uspace/srv/bd/hr/metadata/native.c +++ b/uspace/srv/bd/hr/metadata/native.c @@ -375,20 +375,13 @@ static void meta_native_inc_counter(hr_volume_t *vol) fibril_mutex_unlock(&vol->md_lock); } -/* - * XXX: finish this fcn documentation - * - * Returns ENOMEM else EOK - */ static errno_t meta_native_save(hr_volume_t *vol, bool with_state_callback) { HR_DEBUG("%s()", __func__); errno_t rc = EOK; - void *md_block = calloc(1, vol->bsize); - if (md_block == NULL) - return ENOMEM; + void *md_block = hr_calloc_waitok(1, vol->bsize); hr_metadata_t *md = (hr_metadata_t *)vol->in_mem_md; From e0695cef2a4a4392f323e3f0212caa45f2b409ee Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 23 Jun 2025 18:47:52 +0200 Subject: [PATCH 275/324] hr: save REBUILD position --- uspace/srv/bd/hr/hr.c | 4 +- uspace/srv/bd/hr/metadata/native.c | 30 ++++++++++--- uspace/srv/bd/hr/metadata/native.h | 2 + uspace/srv/bd/hr/raid1.c | 32 ++++++++------ uspace/srv/bd/hr/raid5.c | 28 +++++++++--- uspace/srv/bd/hr/util.c | 71 +++++++++++++++++------------- uspace/srv/bd/hr/var.h | 7 +++ 7 files changed, 115 insertions(+), 59 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index a530a21bd9..bbdc312827 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -154,9 +154,7 @@ static void hr_create_srv(ipc_call_t *icall) if (rc != EOK) goto error; - rc = vol->meta_ops->save(vol, WITH_STATE_CALLBACK); - if (rc != EOK) - goto error; + vol->meta_ops->save(vol, WITH_STATE_CALLBACK); rc = hr_register_volume(vol); if (rc != EOK) diff --git a/uspace/srv/bd/hr/metadata/native.c b/uspace/srv/bd/hr/metadata/native.c index 9bf083dc51..eeeb3802ac 100644 --- a/uspace/srv/bd/hr/metadata/native.c +++ b/uspace/srv/bd/hr/metadata/native.c @@ -170,10 +170,19 @@ static errno_t meta_native_init_meta2vol(const list_t *list, hr_volume_t *vol) vol->extents[iter_meta->index].svc_id = iter->svc_id; iter->fini = false; - if (iter_meta->counter == max_counter_val) - vol->extents[iter_meta->index].state = HR_EXT_ONLINE; - else - vol->extents[iter_meta->index].state = HR_EXT_INVALID; + hr_ext_state_t final_ext_state = HR_EXT_INVALID; + if (iter_meta->counter == max_counter_val) { + if (iter_meta->rebuild_pos > 0) { + final_ext_state = HR_EXT_REBUILD; + vol->rebuild_blk = iter_meta->rebuild_pos; + printf("REBUILD SHOULD RESUME at %lu\n", + vol->rebuild_blk); + } else { + final_ext_state = HR_EXT_ONLINE; + } + } + + vol->extents[iter_meta->index].state = final_ext_state; } for (size_t i = 0; i < vol->extent_no; i++) { @@ -205,6 +214,7 @@ static void meta_native_encode(void *md_v, void *block) metadata->truncated_blkno); scratch_md.data_offset = host2uint64_t_le(metadata->data_offset); scratch_md.counter = host2uint64_t_le(metadata->counter); + scratch_md.rebuild_pos = host2uint64_t_le(metadata->rebuild_pos); scratch_md.version = host2uint32_t_le(metadata->version); scratch_md.extent_no = host2uint32_t_le(metadata->extent_no); scratch_md.index = host2uint32_t_le(metadata->index); @@ -239,6 +249,7 @@ static errno_t meta_native_decode(const void *block, void *md_v) scratch_md.truncated_blkno); metadata->data_offset = uint64_t_le2host(scratch_md.data_offset); metadata->counter = uint64_t_le2host(scratch_md.counter); + metadata->rebuild_pos = uint64_t_le2host(scratch_md.rebuild_pos); metadata->version = uint32_t_le2host(scratch_md.version); metadata->extent_no = uint32_t_le2host(scratch_md.extent_no); metadata->index = uint32_t_le2host(scratch_md.index); @@ -248,6 +259,9 @@ static errno_t meta_native_decode(const void *block, void *md_v) metadata->bsize = uint32_t_le2host(scratch_md.bsize); memcpy(metadata->devname, scratch_md.devname, HR_DEVNAME_LEN); + if (metadata->version != 1) + return EINVAL; + return EOK; } @@ -393,9 +407,9 @@ static errno_t meta_native_save(hr_volume_t *vol, bool with_state_callback) hr_extent_t *ext = &vol->extents[i]; fibril_rwlock_read_lock(&vol->states_lock); + hr_ext_state_t s = ext->state; - /* TODO: special case for REBUILD */ - if (ext->state != HR_EXT_ONLINE) { + if (s != HR_EXT_ONLINE && s != HR_EXT_REBUILD) { fibril_rwlock_read_unlock(&vol->states_lock); continue; } @@ -403,6 +417,10 @@ static errno_t meta_native_save(hr_volume_t *vol, bool with_state_callback) fibril_rwlock_read_unlock(&vol->states_lock); md->index = i; + if (s == HR_EXT_REBUILD) + md->rebuild_pos = vol->rebuild_blk; + else + md->rebuild_pos = 0; meta_native_encode(md, md_block); rc = meta_native_write_block(ext->svc_id, md_block); if (rc != EOK && with_state_callback) diff --git a/uspace/srv/bd/hr/metadata/native.h b/uspace/srv/bd/hr/metadata/native.h index 7519d3e734..85857acb6d 100644 --- a/uspace/srv/bd/hr/metadata/native.h +++ b/uspace/srv/bd/hr/metadata/native.h @@ -60,6 +60,8 @@ struct hr_metadata { uint64_t data_offset; uint64_t counter; + uint64_t rebuild_pos; + uint32_t version; /* XXX: yet unused */ uint32_t extent_no; uint32_t index; /* index of extent in volume */ diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 98ed43cf1e..0fbecdf8bf 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -152,7 +152,7 @@ void hr_raid1_vol_state_eval(hr_volume_t *vol) return; vol->meta_ops->inc_counter(vol); - (void)vol->meta_ops->save(vol, WITH_STATE_CALLBACK); + vol->meta_ops->save(vol, WITH_STATE_CALLBACK); hr_raid1_vol_state_eval_forced(vol); } @@ -193,6 +193,8 @@ static void hr_raid1_vol_state_eval_forced(hr_volume_t *vol) size_t invalid_no = hr_count_extents(vol, HR_EXT_INVALID); + size_t rebuild_no = hr_count_extents(vol, HR_EXT_REBUILD); + fibril_mutex_lock(&vol->hotspare_lock); size_t hs_no = vol->hotspare_no; fibril_mutex_unlock(&vol->hotspare_lock); @@ -215,7 +217,7 @@ static void hr_raid1_vol_state_eval_forced(hr_volume_t *vol) } if (old_state != HR_VOL_REBUILD) { - if (hs_no > 0 || invalid_no > 0) { + if (hs_no > 0 || invalid_no > 0 || rebuild_no > 0) { fid_t fib = fibril_create(hr_raid1_rebuild, vol); if (fib == 0) @@ -442,10 +444,6 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, hr_volume_t *vol, return rc; } -/* - * Put the last HOTSPARE extent in place - * of first that != ONLINE, and start the rebuild. - */ static errno_t hr_raid1_rebuild(void *arg) { HR_DEBUG("%s()", __func__); @@ -462,12 +460,12 @@ static errno_t hr_raid1_rebuild(void *arg) rebuild_ext = &vol->extents[rebuild_idx]; - size_t left = vol->data_blkno; + size_t left = vol->data_blkno - vol->rebuild_blk; size_t max_blks = DATA_XFER_LIMIT / vol->bsize; buf = hr_malloc_waitok(max_blks * vol->bsize); size_t cnt; - uint64_t ba = 0; + uint64_t ba = vol->rebuild_blk; hr_add_data_offset(vol, &ba); /* @@ -486,6 +484,10 @@ static errno_t hr_raid1_rebuild(void *arg) hr_range_lock_t *rl = NULL; + HR_NOTE("\"%s\": REBUILD started on extent no. %zu at block %lu.\n", + vol->devname, rebuild_idx, ba); + + uint64_t written = 0; unsigned int percent, old_percent = 100; while (left != 0) { cnt = min(max_blks, left); @@ -516,8 +518,14 @@ static errno_t hr_raid1_rebuild(void *arg) vol->devname, percent); } + if (written * vol->bsize > HR_REBUILD_SAVE_BYTES) { + vol->meta_ops->save(vol, WITH_STATE_CALLBACK); + written = 0; + } + hr_range_lock_release(rl); + written += cnt; ba += cnt; left -= cnt; old_percent = percent; @@ -530,19 +538,17 @@ static errno_t hr_raid1_rebuild(void *arg) hr_update_ext_state(vol, rebuild_idx, HR_EXT_ONLINE); + atomic_store_explicit(&vol->rebuild_blk, 0, memory_order_relaxed); + hr_mark_vol_state_dirty(vol); fibril_rwlock_write_unlock(&vol->states_lock); - - /* (void)vol->meta_ops->save(vol, WITH_STATE_CALLBACK); */ - end: fibril_rwlock_read_unlock(&vol->extents_lock); hr_raid1_vol_state_eval(vol); - if (buf != NULL) - free(buf); + free(buf); return rc; } diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 7d8d5d8381..f71aeb1fd6 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -149,7 +149,7 @@ void hr_raid5_vol_state_eval(hr_volume_t *vol) return; vol->meta_ops->inc_counter(vol); - (void)vol->meta_ops->save(vol, WITH_STATE_CALLBACK); + vol->meta_ops->save(vol, WITH_STATE_CALLBACK); hr_raid5_vol_state_eval_forced(vol); } @@ -610,6 +610,8 @@ static void hr_raid5_vol_state_eval_forced(hr_volume_t *vol) size_t invalid_no = hr_count_extents(vol, HR_EXT_INVALID); + size_t rebuild_no = hr_count_extents(vol, HR_EXT_REBUILD); + fibril_mutex_lock(&vol->hotspare_lock); size_t hs_no = vol->hotspare_no; fibril_mutex_unlock(&vol->hotspare_lock); @@ -624,7 +626,7 @@ static void hr_raid5_vol_state_eval_forced(hr_volume_t *vol) hr_update_vol_state(vol, HR_VOL_DEGRADED); if (state != HR_VOL_REBUILD) { - if (hs_no > 0 || invalid_no > 0) { + if (hs_no > 0 || invalid_no > 0 || rebuild_no > 0) { fid_t fib = fibril_create(hr_raid5_rebuild, vol); if (fib == 0) @@ -719,13 +721,15 @@ static errno_t hr_raid5_rebuild(void *arg) return rc; uint64_t max_blks = DATA_XFER_LIMIT / vol->bsize; - uint64_t left = vol->data_blkno / (vol->extent_no - 1); + uint64_t left = + vol->data_blkno / (vol->extent_no - 1) - vol->rebuild_blk; buf = hr_malloc_waitok(max_blks * vol->bsize); xorbuf = hr_malloc_waitok(max_blks * vol->bsize); uint64_t strip_size = vol->strip_size / vol->bsize; /* in blocks */ - uint64_t ba = 0, cnt; + size_t cnt; + uint64_t ba = vol->rebuild_blk; hr_add_data_offset(vol, &ba); /* @@ -746,6 +750,10 @@ static errno_t hr_raid5_rebuild(void *arg) hr_stripe_t *stripe = hr_create_stripes(vol, max_blks * vol->bsize, 1, false); + HR_NOTE("\"%s\": REBUILD started on extent no. %zu at block %lu.\n", + vol->devname, rebuild_idx, ba); + + uint64_t written = 0; unsigned int percent, old_percent = 100; while (left != 0) { cnt = min(left, max_blks); @@ -809,11 +817,18 @@ static errno_t hr_raid5_rebuild(void *arg) vol->devname, percent); } + if (written * vol->bsize > HR_REBUILD_SAVE_BYTES) { + vol->meta_ops->save(vol, WITH_STATE_CALLBACK); + written = 0; + } + hr_range_lock_release(rl); hr_reset_stripe(stripe); + written += cnt; ba += cnt; left -= cnt; + old_percent = percent; /* * Let other IO requests be served @@ -828,12 +843,11 @@ static errno_t hr_raid5_rebuild(void *arg) hr_update_ext_state(vol, rebuild_idx, HR_EXT_ONLINE); + atomic_store_explicit(&vol->rebuild_blk, 0, memory_order_relaxed); + hr_mark_vol_state_dirty(vol); fibril_rwlock_write_unlock(&vol->states_lock); - - /* (void)vol->meta_ops->save(vol, WITH_STATE_CALLBACK); */ - end: fibril_rwlock_read_unlock(&vol->extents_lock); diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 5fbe4cff24..fb93054eb5 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -280,7 +280,7 @@ errno_t hr_remove_volume(service_id_t svc_id) fibril_rwlock_write_unlock(&hr_volumes_lock); /* save metadata, but we don't care about states anymore */ - (void)vol->meta_ops->save(vol, NO_STATE_CALLBACK); + vol->meta_ops->save(vol, NO_STATE_CALLBACK); HR_NOTE("deactivating volume \"%s\"\n", vol->devname); @@ -1116,6 +1116,7 @@ errno_t hr_sync_extents(hr_volume_t *vol) errno_t hr_init_rebuild(hr_volume_t *vol, size_t *rebuild_idx) { errno_t rc = EOK; + size_t bad = vol->extent_no; if (vol->level == HR_LVL_0) return EINVAL; @@ -1124,18 +1125,23 @@ errno_t hr_init_rebuild(hr_volume_t *vol, size_t *rebuild_idx) fibril_rwlock_write_lock(&vol->states_lock); fibril_mutex_lock(&vol->hotspare_lock); - size_t bad = vol->extent_no; + if (vol->state != HR_VOL_DEGRADED) { + rc = EINVAL; + goto error; + } + + size_t rebuild = vol->extent_no; for (size_t i = 0; i < vol->extent_no; i++) { - if (vol->extents[i].state != HR_EXT_ONLINE) { - bad = i; + if (vol->extents[i].state == HR_EXT_REBUILD) { + rebuild = i; break; } } - if (bad == vol->extent_no) - rc = EINVAL; - else if (vol->state != HR_VOL_DEGRADED) - rc = EINVAL; + if (rebuild < vol->extent_no) { + bad = rebuild; + goto init_rebuild; + } size_t invalid = vol->extent_no; for (size_t i = 0; i < vol->extent_no; i++) { @@ -1145,33 +1151,39 @@ errno_t hr_init_rebuild(hr_volume_t *vol, size_t *rebuild_idx) } } - if (invalid < vol->extent_no) + if (invalid < vol->extent_no) { bad = invalid; + goto init_rebuild; + } - if (bad != invalid && vol->hotspare_no == 0) - rc = EINVAL; + for (size_t i = 0; i < vol->extent_no; i++) { + if (vol->extents[i].state != HR_EXT_ONLINE) { + bad = i; + break; + } + } - if (rc != EOK) + if (bad == vol->extent_no || vol->hotspare_no == 0) { + rc = EINVAL; goto error; + } - if (bad != invalid) { - size_t hotspare_idx = vol->hotspare_no - 1; + size_t hotspare_idx = vol->hotspare_no - 1; - hr_ext_state_t hs_state = vol->hotspares[hotspare_idx].state; - if (hs_state != HR_EXT_HOTSPARE) { - HR_ERROR("hr_raid1_rebuild(): invalid hotspare" - "state \"%s\", aborting rebuild\n", - hr_get_ext_state_str(hs_state)); - rc = EINVAL; - goto error; - } + hr_ext_state_t hs_state = vol->hotspares[hotspare_idx].state; + if (hs_state != HR_EXT_HOTSPARE) { + HR_ERROR("hr_raid1_rebuild(): invalid hotspare" + "state \"%s\", aborting rebuild\n", + hr_get_ext_state_str(hs_state)); + rc = EINVAL; + goto error; + } - rc = hr_swap_hs(vol, bad, hotspare_idx); - if (rc != EOK) { - HR_ERROR("hr_raid1_rebuild(): swapping " - "hotspare failed, aborting rebuild\n"); - goto error; - } + rc = hr_swap_hs(vol, bad, hotspare_idx); + if (rc != EOK) { + HR_ERROR("hr_raid1_rebuild(): swapping " + "hotspare failed, aborting rebuild\n"); + goto error; } hr_extent_t *rebuild_ext = &vol->extents[bad]; @@ -1179,8 +1191,7 @@ errno_t hr_init_rebuild(hr_volume_t *vol, size_t *rebuild_idx) HR_DEBUG("hr_raid1_rebuild(): starting REBUILD on extent no. %zu " "(%" PRIun ")\n", bad, rebuild_ext->svc_id); - atomic_store_explicit(&vol->rebuild_blk, 0, memory_order_relaxed); - +init_rebuild: hr_update_ext_state(vol, bad, HR_EXT_REBUILD); hr_update_vol_state(vol, HR_VOL_REBUILD); diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index 8961829710..9a2d11b79b 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -49,6 +49,13 @@ #define NAME "hr" #define HR_STRIP_SIZE DATA_XFER_LIMIT +/* + * During a rebuild operation, we save the rebuild + * position this each many bytes. Currently each + * 10 MiB. + */ +#define HR_REBUILD_SAVE_BYTES (10U * 1024 * 1024) + struct hr_volume; typedef struct hr_volume hr_volume_t; typedef struct hr_stripe hr_stripe_t; From 6a8c1569d31b7ba25b64484de060d2f88525c8d9 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 23 Jun 2025 20:31:18 +0200 Subject: [PATCH 276/324] hr: add option to save metadata on single extent --- .../bd/hr/metadata/foreign/geom/hr_g_mirror.c | 10 +++ .../bd/hr/metadata/foreign/geom/hr_g_stripe.c | 10 +++ .../metadata/foreign/softraid/hr_softraid.c | 10 +++ uspace/srv/bd/hr/metadata/native.c | 61 +++++++++++-------- uspace/srv/bd/hr/raid1.c | 3 +- uspace/srv/bd/hr/raid5.c | 3 +- uspace/srv/bd/hr/superblock.h | 1 + 7 files changed, 70 insertions(+), 28 deletions(-) diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c index 1eb3c8019f..8962d3b2de 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c @@ -63,6 +63,7 @@ static bool meta_gmirror_has_valid_magic(const void *); static bool meta_gmirror_compare_uuids(const void *, const void *); static void meta_gmirror_inc_counter(hr_volume_t *); static errno_t meta_gmirror_save(hr_volume_t *, bool); +static errno_t meta_gmirror_save_ext(hr_volume_t *, size_t, bool); static const char *meta_gmirror_get_devname(const void *); static hr_level_t meta_gmirror_get_level(const void *); static uint64_t meta_gmirror_get_data_offset(void); @@ -83,6 +84,7 @@ hr_superblock_ops_t metadata_gmirror_ops = { .compare_uuids = meta_gmirror_compare_uuids, .inc_counter = meta_gmirror_inc_counter, .save = meta_gmirror_save, + .save_ext = meta_gmirror_save_ext, .get_devname = meta_gmirror_get_devname, .get_level = meta_gmirror_get_level, .get_data_offset = meta_gmirror_get_data_offset, @@ -311,6 +313,14 @@ static errno_t meta_gmirror_save(hr_volume_t *vol, bool with_state_callback) return ENOTSUP; } +static errno_t meta_gmirror_save_ext(hr_volume_t *vol, size_t ext_idx, + bool with_state_callback) +{ + HR_DEBUG("%s()", __func__); + + return ENOTSUP; +} + static const char *meta_gmirror_get_devname(const void *md_v) { const struct g_mirror_metadata *md = md_v; diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c index 6f2fc8f0ea..3d254d3ebe 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c @@ -63,6 +63,7 @@ static bool meta_gstripe_has_valid_magic(const void *); static bool meta_gstripe_compare_uuids(const void *, const void *); static void meta_gstripe_inc_counter(hr_volume_t *); static errno_t meta_gstripe_save(hr_volume_t *, bool); +static errno_t meta_gstripe_save_ext(hr_volume_t *, size_t, bool); static const char *meta_gstripe_get_devname(const void *); static hr_level_t meta_gstripe_get_level(const void *); static uint64_t meta_gstripe_get_data_offset(void); @@ -83,6 +84,7 @@ hr_superblock_ops_t metadata_gstripe_ops = { .compare_uuids = meta_gstripe_compare_uuids, .inc_counter = meta_gstripe_inc_counter, .save = meta_gstripe_save, + .save_ext = meta_gstripe_save_ext, .get_devname = meta_gstripe_get_devname, .get_level = meta_gstripe_get_level, .get_data_offset = meta_gstripe_get_data_offset, @@ -297,6 +299,14 @@ static errno_t meta_gstripe_save(hr_volume_t *vol, bool with_state_callback) return ENOTSUP; } +static errno_t meta_gstripe_save_ext(hr_volume_t *vol, size_t ext_idx, + bool with_state_callback) +{ + HR_DEBUG("%s()", __func__); + + return ENOTSUP; +} + static const char *meta_gstripe_get_devname(const void *md_v) { const struct g_stripe_metadata *md = md_v; diff --git a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c index da9bd0f6b0..05b2a77c05 100644 --- a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c +++ b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c @@ -63,6 +63,7 @@ static bool meta_softraid_has_valid_magic(const void *); static bool meta_softraid_compare_uuids(const void *, const void *); static void meta_softraid_inc_counter(hr_volume_t *); static errno_t meta_softraid_save(hr_volume_t *, bool); +static errno_t meta_softraid_save_ext(hr_volume_t *, size_t, bool); static const char *meta_softraid_get_devname(const void *); static hr_level_t meta_softraid_get_level(const void *); static uint64_t meta_softraid_get_data_offset(void); @@ -83,6 +84,7 @@ hr_superblock_ops_t metadata_softraid_ops = { .compare_uuids = meta_softraid_compare_uuids, .inc_counter = meta_softraid_inc_counter, .save = meta_softraid_save, + .save_ext = meta_softraid_save_ext, .get_devname = meta_softraid_get_devname, .get_level = meta_softraid_get_level, .get_data_offset = meta_softraid_get_data_offset, @@ -436,6 +438,14 @@ static errno_t meta_softraid_save(hr_volume_t *vol, bool with_state_callback) return ENOTSUP; } +static errno_t meta_softraid_save_ext(hr_volume_t *vol, size_t ext_idx, + bool with_state_callback) +{ + HR_DEBUG("%s()", __func__); + + return ENOTSUP; +} + static const char *meta_softraid_get_devname(const void *md_v) { const struct sr_metadata *md = md_v; diff --git a/uspace/srv/bd/hr/metadata/native.c b/uspace/srv/bd/hr/metadata/native.c index eeeb3802ac..51d303e64b 100644 --- a/uspace/srv/bd/hr/metadata/native.c +++ b/uspace/srv/bd/hr/metadata/native.c @@ -64,6 +64,7 @@ static bool meta_native_has_valid_magic(const void *); static bool meta_native_compare_uuids(const void *, const void *); static void meta_native_inc_counter(hr_volume_t *); static errno_t meta_native_save(hr_volume_t *, bool); +static errno_t meta_native_save_ext(hr_volume_t *, size_t, bool); static const char *meta_native_get_devname(const void *); static hr_level_t meta_native_get_level(const void *); static uint64_t meta_native_get_data_offset(void); @@ -85,6 +86,7 @@ hr_superblock_ops_t metadata_native_ops = { .compare_uuids = meta_native_compare_uuids, .inc_counter = meta_native_inc_counter, .save = meta_native_save, + .save_ext = meta_native_save_ext, .get_devname = meta_native_get_devname, .get_level = meta_native_get_level, .get_data_offset = meta_native_get_data_offset, @@ -393,43 +395,50 @@ static errno_t meta_native_save(hr_volume_t *vol, bool with_state_callback) { HR_DEBUG("%s()", __func__); - errno_t rc = EOK; + fibril_rwlock_read_lock(&vol->extents_lock); - void *md_block = hr_calloc_waitok(1, vol->bsize); + for (size_t i = 0; i < vol->extent_no; i++) + meta_native_save_ext(vol, i, with_state_callback); - hr_metadata_t *md = (hr_metadata_t *)vol->in_mem_md; + fibril_rwlock_read_unlock(&vol->extents_lock); - fibril_rwlock_read_lock(&vol->extents_lock); + return EOK; +} - fibril_mutex_lock(&vol->md_lock); +static errno_t meta_native_save_ext(hr_volume_t *vol, size_t ext_idx, + bool with_state_callback) +{ + HR_DEBUG("%s()", __func__); - for (size_t i = 0; i < vol->extent_no; i++) { - hr_extent_t *ext = &vol->extents[i]; + assert(fibril_rwlock_is_locked(&vol->extents_lock)); - fibril_rwlock_read_lock(&vol->states_lock); - hr_ext_state_t s = ext->state; + void *md_block = hr_calloc_waitok(1, vol->bsize); - if (s != HR_EXT_ONLINE && s != HR_EXT_REBUILD) { - fibril_rwlock_read_unlock(&vol->states_lock); - continue; - } + hr_metadata_t *md = (hr_metadata_t *)vol->in_mem_md; - fibril_rwlock_read_unlock(&vol->states_lock); - - md->index = i; - if (s == HR_EXT_REBUILD) - md->rebuild_pos = vol->rebuild_blk; - else - md->rebuild_pos = 0; - meta_native_encode(md, md_block); - rc = meta_native_write_block(ext->svc_id, md_block); - if (rc != EOK && with_state_callback) - vol->hr_ops.ext_state_cb(vol, i, rc); + hr_extent_t *ext = &vol->extents[ext_idx]; + + fibril_rwlock_read_lock(&vol->states_lock); + hr_ext_state_t s = ext->state; + fibril_rwlock_read_unlock(&vol->states_lock); + + if (s != HR_EXT_ONLINE && s != HR_EXT_REBUILD) { + return EINVAL; } - fibril_mutex_unlock(&vol->md_lock); + fibril_mutex_lock(&vol->md_lock); - fibril_rwlock_read_unlock(&vol->extents_lock); + md->index = ext_idx; + if (s == HR_EXT_REBUILD) + md->rebuild_pos = vol->rebuild_blk; + else + md->rebuild_pos = 0; + meta_native_encode(md, md_block); + errno_t rc = meta_native_write_block(ext->svc_id, md_block); + if (rc != EOK && with_state_callback) + vol->hr_ops.ext_state_cb(vol, ext_idx, rc); + + fibril_mutex_unlock(&vol->md_lock); if (with_state_callback) vol->hr_ops.vol_state_eval(vol); diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 0fbecdf8bf..147058e344 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -519,7 +519,8 @@ static errno_t hr_raid1_rebuild(void *arg) } if (written * vol->bsize > HR_REBUILD_SAVE_BYTES) { - vol->meta_ops->save(vol, WITH_STATE_CALLBACK); + vol->meta_ops->save_ext(vol, rebuild_idx, + WITH_STATE_CALLBACK); written = 0; } diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index f71aeb1fd6..d197e593ff 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -818,7 +818,8 @@ static errno_t hr_raid5_rebuild(void *arg) } if (written * vol->bsize > HR_REBUILD_SAVE_BYTES) { - vol->meta_ops->save(vol, WITH_STATE_CALLBACK); + vol->meta_ops->save_ext(vol, rebuild_idx, + WITH_STATE_CALLBACK); written = 0; } diff --git a/uspace/srv/bd/hr/superblock.h b/uspace/srv/bd/hr/superblock.h index 7c70399594..98ea8e3b17 100644 --- a/uspace/srv/bd/hr/superblock.h +++ b/uspace/srv/bd/hr/superblock.h @@ -55,6 +55,7 @@ typedef struct hr_superblock_ops { bool (*compare_uuids)(const void *, const void *); void (*inc_counter)(hr_volume_t *); errno_t (*save)(hr_volume_t *, bool); + errno_t (*save_ext)(hr_volume_t *, size_t, bool); const char *(*get_devname)(const void *); hr_level_t (*get_level)(const void *); uint64_t (*get_data_offset)(void); From 62a875661aa687078b29c7a2812276bddab8f456 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 23 Jun 2025 20:39:11 +0200 Subject: [PATCH 277/324] hr: metadata: use ENOMEM safe block I/O wrappers --- uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c | 5 +++-- uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c | 5 +++-- uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c | 5 +++-- uspace/srv/bd/hr/metadata/native.c | 5 +++-- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c index 8962d3b2de..903651038b 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c @@ -47,6 +47,7 @@ #include #include +#include "../../../io.h" #include "../../../util.h" #include "../../../var.h" @@ -221,7 +222,7 @@ static errno_t meta_gmirror_get_block(service_id_t dev, void **rblock) if (block == NULL) return ENOMEM; - rc = block_read_direct(dev, blkno - 1, 1, block); + rc = hr_read_direct(dev, blkno - 1, 1, block); /* * XXX: here maybe call vol state event or the state callback... * @@ -258,7 +259,7 @@ static errno_t meta_gmirror_write_block(service_id_t dev, const void *block) if (blkno < 1) return EINVAL; - rc = block_write_direct(dev, blkno - 1, 1, block); + rc = hr_write_direct(dev, blkno - 1, 1, block); return rc; } diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c index 3d254d3ebe..d21c753152 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c @@ -47,6 +47,7 @@ #include #include +#include "../../../io.h" #include "../../../util.h" #include "../../../var.h" @@ -223,7 +224,7 @@ static errno_t meta_gstripe_get_block(service_id_t dev, void **rblock) if (block == NULL) return ENOMEM; - rc = block_read_direct(dev, blkno - 1, 1, block); + rc = hr_read_direct(dev, blkno - 1, 1, block); /* * XXX: here maybe call vol state event or the state callback... * @@ -260,7 +261,7 @@ static errno_t meta_gstripe_write_block(service_id_t dev, const void *block) if (blkno < 1) return EINVAL; - rc = block_write_direct(dev, blkno - 1, 1, block); + rc = hr_write_direct(dev, blkno - 1, 1, block); return rc; } diff --git a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c index 05b2a77c05..580fc06f0f 100644 --- a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c +++ b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c @@ -47,6 +47,7 @@ #include #include +#include "../../../io.h" #include "../../../util.h" #include "../../../var.h" @@ -360,7 +361,7 @@ static errno_t meta_softraid_get_block(service_id_t dev, void **rblock) if (block == NULL) return ENOMEM; - rc = block_read_direct(dev, SR_META_OFFSET, SR_META_SIZE, block); + rc = hr_read_direct(dev, SR_META_OFFSET, SR_META_SIZE, block); if (rc != EOK) { free(block); return rc; @@ -392,7 +393,7 @@ static errno_t meta_softraid_write_block(service_id_t dev, const void *block) if (blkno < SR_META_OFFSET + SR_META_SIZE) return EINVAL; - rc = block_write_direct(dev, SR_META_OFFSET, SR_META_SIZE, block); + rc = hr_write_direct(dev, SR_META_OFFSET, SR_META_SIZE, block); return rc; } diff --git a/uspace/srv/bd/hr/metadata/native.c b/uspace/srv/bd/hr/metadata/native.c index 51d303e64b..3f90b09557 100644 --- a/uspace/srv/bd/hr/metadata/native.c +++ b/uspace/srv/bd/hr/metadata/native.c @@ -47,6 +47,7 @@ #include #include +#include "../io.h" #include "../util.h" #include "../var.h" @@ -297,7 +298,7 @@ static errno_t meta_native_get_block(service_id_t dev, void **rblock) if (block == NULL) return ENOMEM; - rc = block_read_direct(dev, blkno - 1, HR_NATIVE_META_SIZE, block); + rc = hr_read_direct(dev, blkno - 1, HR_NATIVE_META_SIZE, block); /* * XXX: here maybe call vol state event or the state callback... * @@ -334,7 +335,7 @@ static errno_t meta_native_write_block(service_id_t dev, const void *block) if (blkno < HR_NATIVE_META_SIZE) return EINVAL; - rc = block_write_direct(dev, blkno - 1, HR_NATIVE_META_SIZE, block); + rc = hr_write_direct(dev, blkno - 1, HR_NATIVE_META_SIZE, block); return rc; } From 3702c322639a50b16c81fa6003a0f62a0e365dc2 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 23 Jun 2025 20:41:38 +0200 Subject: [PATCH 278/324] hr: metadata/foreign/softraid: remove old comment --- uspace/srv/bd/hr/metadata/foreign/softraid/softraid.c | 1 - 1 file changed, 1 deletion(-) diff --git a/uspace/srv/bd/hr/metadata/foreign/softraid/softraid.c b/uspace/srv/bd/hr/metadata/foreign/softraid/softraid.c index 06b1147fc0..338bfd9eae 100644 --- a/uspace/srv/bd/hr/metadata/foreign/softraid/softraid.c +++ b/uspace/srv/bd/hr/metadata/foreign/softraid/softraid.c @@ -75,7 +75,6 @@ sr_meta_print(const struct sr_metadata *m) struct sr_meta_chunk *mc; struct sr_meta_opt_hdr *omh; - /* TODO XXX: use PRI for portability */ printf("\tssd_magic 0x%" PRIx64 "\n", m->ssdi.ssd_magic); printf("\tssd_version %" PRId32 "\n", m->ssdi.ssd_version); printf("\tssd_vol_flags 0x%" PRIx32 "\n", m->ssdi.ssd_vol_flags); From c69cbefaf6ce6c2791016356238e9b419196e39c Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 27 Jun 2025 18:35:16 +0200 Subject: [PATCH 279/324] hr: metadata/native: remove data_offset Since native metadata are stored in the last block, it is redundant to have data_offset saved as it will always be 0 for now. --- uspace/srv/bd/hr/metadata/native.c | 10 +--------- uspace/srv/bd/hr/metadata/native.h | 25 +++++++++++++------------ 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/uspace/srv/bd/hr/metadata/native.c b/uspace/srv/bd/hr/metadata/native.c index 3f90b09557..34105221e8 100644 --- a/uspace/srv/bd/hr/metadata/native.c +++ b/uspace/srv/bd/hr/metadata/native.c @@ -121,13 +121,10 @@ static errno_t meta_native_init_vol2meta(const hr_volume_t *vol, void *md_v) if (rc != EOK) return rc; - /* XXX: for now we just copy byte by byte as "encoding" */ memcpy(md->uuid, &uuid, HR_NATIVE_UUID_LEN); - /* uuid_encode(&uuid, metadata->uuid); */ md->data_blkno = vol->data_blkno; md->truncated_blkno = vol->truncated_blkno; - md->data_offset = vol->data_offset; md->extent_no = vol->extent_no; md->level = vol->level; md->layout = vol->layout; @@ -157,7 +154,7 @@ static errno_t meta_native_init_meta2vol(const list_t *list, hr_volume_t *vol) vol->data_blkno = main_meta->data_blkno; vol->truncated_blkno = main_meta->truncated_blkno; - vol->data_offset = main_meta->data_offset; + vol->data_offset = meta_native_get_data_offset(); vol->extent_no = main_meta->extent_no; /* vol->level = main_meta->level; */ /* already set */ vol->layout = main_meta->layout; @@ -210,12 +207,10 @@ static void meta_native_encode(void *md_v, void *block) memcpy(scratch_md.magic, metadata->magic, HR_NATIVE_MAGIC_SIZE); memcpy(scratch_md.uuid, metadata->uuid, HR_NATIVE_UUID_LEN); - /* uuid_decode((uint8_t *)scratch_md.uuid, (uuid_t *)metadata->uuid); */ scratch_md.data_blkno = host2uint64_t_le(metadata->data_blkno); scratch_md.truncated_blkno = host2uint64_t_le( metadata->truncated_blkno); - scratch_md.data_offset = host2uint64_t_le(metadata->data_offset); scratch_md.counter = host2uint64_t_le(metadata->counter); scratch_md.rebuild_pos = host2uint64_t_le(metadata->rebuild_pos); scratch_md.version = host2uint32_t_le(metadata->version); @@ -245,12 +240,10 @@ static errno_t meta_native_decode(const void *block, void *md_v) memcpy(metadata->magic, scratch_md.magic, HR_NATIVE_MAGIC_SIZE); memcpy(metadata->uuid, scratch_md.uuid, HR_NATIVE_UUID_LEN); - /* uuid_decode((uint8_t *)scratch_md.uuid, (uuid_t *)metadata->uuid); */ metadata->data_blkno = uint64_t_le2host(scratch_md.data_blkno); metadata->truncated_blkno = uint64_t_le2host( scratch_md.truncated_blkno); - metadata->data_offset = uint64_t_le2host(scratch_md.data_offset); metadata->counter = uint64_t_le2host(scratch_md.counter); metadata->rebuild_pos = uint64_t_le2host(scratch_md.rebuild_pos); metadata->version = uint32_t_le2host(scratch_md.version); @@ -502,7 +495,6 @@ static void meta_native_dump(const void *md_v) printf("\n"); printf("\tdata_blkno: %" PRIu64 "\n", metadata->data_blkno); printf("\ttruncated_blkno: %" PRIu64 "\n", metadata->truncated_blkno); - printf("\tdata_offset: %" PRIu64 "\n", metadata->data_offset); printf("\tcounter: %" PRIu64 "\n", metadata->counter); printf("\tversion: %" PRIu32 "\n", metadata->version); printf("\textent_no: %" PRIu32 "\n", metadata->extent_no); diff --git a/uspace/srv/bd/hr/metadata/native.h b/uspace/srv/bd/hr/metadata/native.h index 85857acb6d..8f7dfe076d 100644 --- a/uspace/srv/bd/hr/metadata/native.h +++ b/uspace/srv/bd/hr/metadata/native.h @@ -47,6 +47,10 @@ #define HR_NATIVE_MAGIC_STR "HelenRAID" #define HR_NATIVE_MAGIC_SIZE 16 #define HR_NATIVE_UUID_LEN 16 + +/* + * Bump on each superblock update. + */ #define HR_NATIVE_METADATA_VERSION 1 struct hr_metadata { @@ -54,24 +58,21 @@ struct hr_metadata { uint8_t uuid[HR_NATIVE_UUID_LEN]; - uint64_t data_blkno; /* usable blocks */ - uint64_t truncated_blkno; /* size of smallest extent */ - - uint64_t data_offset; - uint64_t counter; - - uint64_t rebuild_pos; - - uint32_t version; /* XXX: yet unused */ + uint32_t version; uint32_t extent_no; - uint32_t index; /* index of extent in volume */ uint32_t level; - uint32_t layout; - uint32_t strip_size; + uint32_t index; /* index of extent in volume */ + uint32_t strip_size; uint32_t bsize; + uint64_t data_blkno; /* usable blocks */ + uint64_t truncated_blkno; /* size of smallest extent */ + + uint64_t counter; + uint64_t rebuild_pos; + char devname[HR_DEVNAME_LEN]; } __attribute__((packed)); From 78433bbc6780846cacf166c1034df23fd5f58768 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 27 Jun 2025 23:01:51 +0200 Subject: [PATCH 280/324] hr: allocate in-memory metadata in format code This will allow some formats to store in-memory copy of metadata for each extent. --- uspace/srv/bd/hr/hr.c | 2 +- .../srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c | 5 ++--- .../srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c | 5 ++--- .../bd/hr/metadata/foreign/softraid/hr_softraid.c | 6 +++--- uspace/srv/bd/hr/metadata/native.c | 14 +++++++++++--- uspace/srv/bd/hr/superblock.h | 2 +- uspace/srv/bd/hr/util.c | 7 ------- 7 files changed, 20 insertions(+), 21 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index bbdc312827..8323bac8ad 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -146,7 +146,7 @@ static void hr_create_srv(ipc_call_t *icall) if (rc != EOK) goto error; - rc = vol->meta_ops->init_vol2meta(vol, vol->in_mem_md); + rc = vol->meta_ops->init_vol2meta(vol); if (rc != EOK) goto error; diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c index 903651038b..a1d5810275 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c @@ -54,7 +54,7 @@ #include "g_mirror.h" static void *meta_gmirror_alloc_struct(void); -static errno_t meta_gmirror_init_vol2meta(const hr_volume_t *, void *); +static errno_t meta_gmirror_init_vol2meta(hr_volume_t *); static errno_t meta_gmirror_init_meta2vol(const list_t *, hr_volume_t *); static void meta_gmirror_encode(void *, void *); static errno_t meta_gmirror_decode(const void *, void *); @@ -100,10 +100,9 @@ static void *meta_gmirror_alloc_struct(void) return calloc(1, sizeof(struct g_mirror_metadata)); } -static errno_t meta_gmirror_init_vol2meta(const hr_volume_t *vol, void *md_v) +static errno_t meta_gmirror_init_vol2meta(hr_volume_t *vol) { (void)vol; - (void)md_v; return ENOTSUP; } diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c index d21c753152..7e18ae7362 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c @@ -54,7 +54,7 @@ #include "g_stripe.h" static void *meta_gstripe_alloc_struct(void); -static errno_t meta_gstripe_init_vol2meta(const hr_volume_t *, void *); +static errno_t meta_gstripe_init_vol2meta(hr_volume_t *); static errno_t meta_gstripe_init_meta2vol(const list_t *, hr_volume_t *); static void meta_gstripe_encode(void *, void *); static errno_t meta_gstripe_decode(const void *, void *); @@ -100,10 +100,9 @@ static void *meta_gstripe_alloc_struct(void) return calloc(1, sizeof(struct g_stripe_metadata)); } -static errno_t meta_gstripe_init_vol2meta(const hr_volume_t *vol, void *md_v) +static errno_t meta_gstripe_init_vol2meta(hr_volume_t *vol) { (void)vol; - (void)md_v; return ENOTSUP; } diff --git a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c index 580fc06f0f..8a98cfd81a 100644 --- a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c +++ b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c @@ -54,7 +54,7 @@ #include "softraidvar.h" static void *meta_softraid_alloc_struct(void); -static errno_t meta_softraid_init_vol2meta(const hr_volume_t *, void *); +static errno_t meta_softraid_init_vol2meta(hr_volume_t *); static errno_t meta_softraid_init_meta2vol(const list_t *, hr_volume_t *); static void meta_softraid_encode(void *, void *); static errno_t meta_softraid_decode(const void *, void *); @@ -100,10 +100,10 @@ static void *meta_softraid_alloc_struct(void) return calloc(1, SR_META_SIZE * DEV_BSIZE); } -static errno_t meta_softraid_init_vol2meta(const hr_volume_t *vol, void *md_v) +static errno_t meta_softraid_init_vol2meta(hr_volume_t *vol) { (void)vol; - (void)md_v; + return ENOTSUP; } diff --git a/uspace/srv/bd/hr/metadata/native.c b/uspace/srv/bd/hr/metadata/native.c index 34105221e8..226613c402 100644 --- a/uspace/srv/bd/hr/metadata/native.c +++ b/uspace/srv/bd/hr/metadata/native.c @@ -54,7 +54,7 @@ #include "native.h" static void *meta_native_alloc_struct(void); -static errno_t meta_native_init_vol2meta(const hr_volume_t *, void *); +static errno_t meta_native_init_vol2meta(hr_volume_t *); static errno_t meta_native_init_meta2vol(const list_t *, hr_volume_t *); static void meta_native_encode(void *, void *); static errno_t meta_native_decode(const void *, void *); @@ -102,11 +102,13 @@ static void *meta_native_alloc_struct(void) return calloc(1, sizeof(hr_metadata_t)); } -static errno_t meta_native_init_vol2meta(const hr_volume_t *vol, void *md_v) +static errno_t meta_native_init_vol2meta(hr_volume_t *vol) { HR_DEBUG("%s()", __func__); - hr_metadata_t *md = md_v; + hr_metadata_t *md = calloc(1, sizeof(*md)); + if (md == NULL) + return ENOMEM; str_cpy(md->magic, HR_NATIVE_MAGIC_SIZE, HR_NATIVE_MAGIC_STR); @@ -132,6 +134,8 @@ static errno_t meta_native_init_vol2meta(const hr_volume_t *vol, void *md_v) md->bsize = vol->bsize; memcpy(md->devname, vol->devname, HR_DEVNAME_LEN); + vol->in_mem_md = md; + return EOK; } @@ -162,6 +166,10 @@ static errno_t meta_native_init_meta2vol(const list_t *list, hr_volume_t *vol) vol->bsize = main_meta->bsize; /* already set */ /* memcpy(vol->devname, main_meta->devname, HR_DEVNAME_LEN); */ + + vol->in_mem_md = calloc(1, sizeof(hr_metadata_t)); + if (vol->in_mem_md == NULL) + return ENOMEM; memcpy(vol->in_mem_md, main_meta, sizeof(hr_metadata_t)); list_foreach(*list, link, struct dev_list_member, iter) { diff --git a/uspace/srv/bd/hr/superblock.h b/uspace/srv/bd/hr/superblock.h index 98ea8e3b17..034a9e44f3 100644 --- a/uspace/srv/bd/hr/superblock.h +++ b/uspace/srv/bd/hr/superblock.h @@ -44,7 +44,7 @@ typedef struct hr_volume hr_volume_t; typedef struct hr_superblock_ops { void *(*alloc_struct)(void); - errno_t (*init_vol2meta)(const hr_volume_t *, void *); + errno_t (*init_vol2meta)(hr_volume_t *); errno_t (*init_meta2vol)(const list_t *, hr_volume_t *); void (*encode)(void *, void *); errno_t (*decode)(const void *, void *); diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index fb93054eb5..c44e16e8c7 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -158,13 +158,6 @@ errno_t hr_create_vol_struct(hr_volume_t **rvol, hr_level_t level, goto error; } - vol->in_mem_md = vol->meta_ops->alloc_struct(); - if (vol->in_mem_md == NULL) { - free(vol->fge); - rc = ENOMEM; - goto error; - } - vol->state = HR_VOL_NONE; fibril_mutex_initialize(&vol->md_lock); From aa9bad8ad7f31ed589ba9008abeb38be019e40c5 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sat, 28 Jun 2025 00:14:37 +0200 Subject: [PATCH 281/324] hr: let each format implement own probe This will allow metadata to have superblocks in different locations accross versions. This also greatly reduces the format handling interface, because now, functions used by the probing done publicly in superblock.c are now used just inside specific metadata format code. --- .../bd/hr/metadata/foreign/geom/hr_g_mirror.c | 237 +++++++----- .../bd/hr/metadata/foreign/geom/hr_g_stripe.c | 223 ++++++----- .../metadata/foreign/softraid/hr_softraid.c | 241 +++++++----- uspace/srv/bd/hr/metadata/native.c | 357 ++++++++++-------- uspace/srv/bd/hr/superblock.c | 31 +- uspace/srv/bd/hr/superblock.h | 11 +- uspace/srv/bd/hr/util.c | 10 +- 7 files changed, 610 insertions(+), 500 deletions(-) diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c index a1d5810275..6d1bd7baed 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c @@ -53,14 +53,17 @@ #include "g_mirror.h" +/* not exposed */ static void *meta_gmirror_alloc_struct(void); -static errno_t meta_gmirror_init_vol2meta(hr_volume_t *); -static errno_t meta_gmirror_init_meta2vol(const list_t *, hr_volume_t *); -static void meta_gmirror_encode(void *, void *); +/* static void meta_gmirror_encode(void *, void *); */ static errno_t meta_gmirror_decode(const void *, void *); static errno_t meta_gmirror_get_block(service_id_t, void **); -static errno_t meta_gmirror_write_block(service_id_t, const void *); +/* static errno_t meta_gmirror_write_block(service_id_t, const void *); */ static bool meta_gmirror_has_valid_magic(const void *); + +static errno_t meta_gmirror_probe(service_id_t, void **); +static errno_t meta_gmirror_init_vol2meta(hr_volume_t *); +static errno_t meta_gmirror_init_meta2vol(const list_t *, hr_volume_t *); static bool meta_gmirror_compare_uuids(const void *, const void *); static void meta_gmirror_inc_counter(hr_volume_t *); static errno_t meta_gmirror_save(hr_volume_t *, bool); @@ -74,14 +77,9 @@ static hr_metadata_type_t meta_gmirror_get_type(void); static void meta_gmirror_dump(const void *); hr_superblock_ops_t metadata_gmirror_ops = { - .alloc_struct = meta_gmirror_alloc_struct, + .probe = meta_gmirror_probe, .init_vol2meta = meta_gmirror_init_vol2meta, .init_meta2vol = meta_gmirror_init_meta2vol, - .encode = meta_gmirror_encode, - .decode = meta_gmirror_decode, - .get_block = meta_gmirror_get_block, - .write_block = meta_gmirror_write_block, - .has_valid_magic = meta_gmirror_has_valid_magic, .compare_uuids = meta_gmirror_compare_uuids, .inc_counter = meta_gmirror_inc_counter, .save = meta_gmirror_save, @@ -95,9 +93,37 @@ hr_superblock_ops_t metadata_gmirror_ops = { .dump = meta_gmirror_dump }; -static void *meta_gmirror_alloc_struct(void) +static errno_t meta_gmirror_probe(service_id_t svc_id, void **rmd) { - return calloc(1, sizeof(struct g_mirror_metadata)); + errno_t rc; + void *meta_block; + + void *metadata_struct = meta_gmirror_alloc_struct(); + if (metadata_struct == NULL) + return ENOMEM; + + rc = meta_gmirror_get_block(svc_id, &meta_block); + if (rc != EOK) + goto error; + + rc = meta_gmirror_decode(meta_block, metadata_struct); + + free(meta_block); + + if (rc != EOK) + goto error; + + if (!meta_gmirror_has_valid_magic(metadata_struct)) { + rc = ENOFS; + goto error; + } + + *rmd = metadata_struct; + return EOK; + +error: + free(metadata_struct); + return ENOFS; } static errno_t meta_gmirror_init_vol2meta(hr_volume_t *vol) @@ -176,12 +202,108 @@ static errno_t meta_gmirror_init_meta2vol(const list_t *list, hr_volume_t *vol) return rc; } +static bool meta_gmirror_compare_uuids(const void *m1_v, const void *m2_v) +{ + const struct g_mirror_metadata *m1 = m1_v; + const struct g_mirror_metadata *m2 = m2_v; + if (m1->md_mid == m2->md_mid) + return true; + + return false; +} + +static void meta_gmirror_inc_counter(hr_volume_t *vol) +{ + fibril_mutex_lock(&vol->md_lock); + + struct g_mirror_metadata *md = vol->in_mem_md; + + /* XXX: probably md_genid and not md_syncid is incremented */ + md->md_genid++; + + fibril_mutex_unlock(&vol->md_lock); +} + +static errno_t meta_gmirror_save(hr_volume_t *vol, bool with_state_callback) +{ + HR_DEBUG("%s()", __func__); + + (void)vol; + (void)with_state_callback; + + /* + * cannot support right now, because would need to store the + * metadata for all disks, because of hardcoded provider names and + * more importantly, disk unique ids + */ + + return ENOTSUP; +} + +static errno_t meta_gmirror_save_ext(hr_volume_t *vol, size_t ext_idx, + bool with_state_callback) +{ + HR_DEBUG("%s()", __func__); + + return ENOTSUP; +} + +static const char *meta_gmirror_get_devname(const void *md_v) +{ + const struct g_mirror_metadata *md = md_v; + + return md->md_name; +} + +static hr_level_t meta_gmirror_get_level(const void *md_v) +{ + (void)md_v; + + return HR_LVL_1; +} + +static uint64_t meta_gmirror_get_data_offset(void) +{ + return 0; +} + +static size_t meta_gmirror_get_size(void) +{ + return 1; +} + +static uint8_t meta_gmirror_get_flags(void) +{ + uint8_t flags = 0; + + return flags; +} + +static hr_metadata_type_t meta_gmirror_get_type(void) +{ + return HR_METADATA_GEOM_MIRROR; +} + +static void meta_gmirror_dump(const void *md_v) +{ + HR_DEBUG("%s()", __func__); + + mirror_metadata_dump(md_v); +} + +static void *meta_gmirror_alloc_struct(void) +{ + return calloc(1, sizeof(struct g_mirror_metadata)); +} + +#if 0 static void meta_gmirror_encode(void *md_v, void *block) { HR_DEBUG("%s()", __func__); mirror_metadata_encode(md_v, block); } +#endif static errno_t meta_gmirror_decode(const void *block, void *md_v) { @@ -236,6 +358,7 @@ static errno_t meta_gmirror_get_block(service_id_t dev, void **rblock) return EOK; } +#if 0 static errno_t meta_gmirror_write_block(service_id_t dev, const void *block) { HR_DEBUG("%s()", __func__); @@ -262,6 +385,7 @@ static errno_t meta_gmirror_write_block(service_id_t dev, const void *block) return rc; } +#endif static bool meta_gmirror_has_valid_magic(const void *md_v) { @@ -275,94 +399,5 @@ static bool meta_gmirror_has_valid_magic(const void *md_v) return true; } -static bool meta_gmirror_compare_uuids(const void *m1_v, const void *m2_v) -{ - const struct g_mirror_metadata *m1 = m1_v; - const struct g_mirror_metadata *m2 = m2_v; - if (m1->md_mid == m2->md_mid) - return true; - - return false; -} - -static void meta_gmirror_inc_counter(hr_volume_t *vol) -{ - fibril_mutex_lock(&vol->md_lock); - - struct g_mirror_metadata *md = vol->in_mem_md; - - /* XXX: probably md_genid and not md_syncid is incremented */ - md->md_genid++; - - fibril_mutex_unlock(&vol->md_lock); -} - -static errno_t meta_gmirror_save(hr_volume_t *vol, bool with_state_callback) -{ - HR_DEBUG("%s()", __func__); - - (void)vol; - (void)with_state_callback; - - /* - * cannot support right now, because would need to store the - * metadata for all disks, because of hardcoded provider names and - * more importantly, disk unique ids - */ - - return ENOTSUP; -} - -static errno_t meta_gmirror_save_ext(hr_volume_t *vol, size_t ext_idx, - bool with_state_callback) -{ - HR_DEBUG("%s()", __func__); - - return ENOTSUP; -} - -static const char *meta_gmirror_get_devname(const void *md_v) -{ - const struct g_mirror_metadata *md = md_v; - - return md->md_name; -} - -static hr_level_t meta_gmirror_get_level(const void *md_v) -{ - (void)md_v; - - return HR_LVL_1; -} - -static uint64_t meta_gmirror_get_data_offset(void) -{ - return 0; -} - -static size_t meta_gmirror_get_size(void) -{ - return 1; -} - -static uint8_t meta_gmirror_get_flags(void) -{ - uint8_t flags = 0; - - return flags; -} - -static hr_metadata_type_t meta_gmirror_get_type(void) -{ - return HR_METADATA_GEOM_MIRROR; -} - -static void meta_gmirror_dump(const void *md_v) -{ - HR_DEBUG("%s()", __func__); - - mirror_metadata_dump(md_v); -} - /** @} */ diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c index 7e18ae7362..df2687eca3 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c @@ -53,14 +53,17 @@ #include "g_stripe.h" +/* not exposed */ static void *meta_gstripe_alloc_struct(void); -static errno_t meta_gstripe_init_vol2meta(hr_volume_t *); -static errno_t meta_gstripe_init_meta2vol(const list_t *, hr_volume_t *); -static void meta_gstripe_encode(void *, void *); +/* static void meta_gstripe_encode(void *, void *); */ static errno_t meta_gstripe_decode(const void *, void *); static errno_t meta_gstripe_get_block(service_id_t, void **); -static errno_t meta_gstripe_write_block(service_id_t, const void *); +/* static errno_t meta_gstripe_write_block(service_id_t, const void *); */ static bool meta_gstripe_has_valid_magic(const void *); + +static errno_t meta_gstripe_probe(service_id_t, void **); +static errno_t meta_gstripe_init_vol2meta(hr_volume_t *); +static errno_t meta_gstripe_init_meta2vol(const list_t *, hr_volume_t *); static bool meta_gstripe_compare_uuids(const void *, const void *); static void meta_gstripe_inc_counter(hr_volume_t *); static errno_t meta_gstripe_save(hr_volume_t *, bool); @@ -74,14 +77,9 @@ static hr_metadata_type_t meta_gstripe_get_type(void); static void meta_gstripe_dump(const void *); hr_superblock_ops_t metadata_gstripe_ops = { - .alloc_struct = meta_gstripe_alloc_struct, + .probe = meta_gstripe_probe, .init_vol2meta = meta_gstripe_init_vol2meta, .init_meta2vol = meta_gstripe_init_meta2vol, - .encode = meta_gstripe_encode, - .decode = meta_gstripe_decode, - .get_block = meta_gstripe_get_block, - .write_block = meta_gstripe_write_block, - .has_valid_magic = meta_gstripe_has_valid_magic, .compare_uuids = meta_gstripe_compare_uuids, .inc_counter = meta_gstripe_inc_counter, .save = meta_gstripe_save, @@ -95,9 +93,37 @@ hr_superblock_ops_t metadata_gstripe_ops = { .dump = meta_gstripe_dump }; -static void *meta_gstripe_alloc_struct(void) +static errno_t meta_gstripe_probe(service_id_t svc_id, void **rmd) { - return calloc(1, sizeof(struct g_stripe_metadata)); + errno_t rc; + void *meta_block; + + void *metadata_struct = meta_gstripe_alloc_struct(); + if (metadata_struct == NULL) + return ENOMEM; + + rc = meta_gstripe_get_block(svc_id, &meta_block); + if (rc != EOK) + goto error; + + rc = meta_gstripe_decode(meta_block, metadata_struct); + + free(meta_block); + + if (rc != EOK) + goto error; + + if (!meta_gstripe_has_valid_magic(metadata_struct)) { + rc = ENOFS; + goto error; + } + + *rmd = metadata_struct; + return EOK; + +error: + free(metadata_struct); + return ENOFS; } static errno_t meta_gstripe_init_vol2meta(hr_volume_t *vol) @@ -177,12 +203,101 @@ static errno_t meta_gstripe_init_meta2vol(const list_t *list, hr_volume_t *vol) return rc; } +static bool meta_gstripe_compare_uuids(const void *md1_v, const void *md2_v) +{ + const struct g_stripe_metadata *md1 = md1_v; + const struct g_stripe_metadata *md2 = md2_v; + if (md1->md_id == md2->md_id) + return true; + + return false; +} + +static void meta_gstripe_inc_counter(hr_volume_t *vol) +{ + (void)vol; +} + +static errno_t meta_gstripe_save(hr_volume_t *vol, bool with_state_callback) +{ + HR_DEBUG("%s()", __func__); + + return ENOTSUP; +} + +static errno_t meta_gstripe_save_ext(hr_volume_t *vol, size_t ext_idx, + bool with_state_callback) +{ + HR_DEBUG("%s()", __func__); + + return ENOTSUP; +} + +static const char *meta_gstripe_get_devname(const void *md_v) +{ + const struct g_stripe_metadata *md = md_v; + + return md->md_name; +} + +static hr_level_t meta_gstripe_get_level(const void *md_v) +{ + (void)md_v; + + return HR_LVL_0; +} + +static uint64_t meta_gstripe_get_data_offset(void) +{ + return 0; +} + +static size_t meta_gstripe_get_size(void) +{ + return 1; +} + +static uint8_t meta_gstripe_get_flags(void) +{ + uint8_t flags = 0; + + return flags; +} + +static hr_metadata_type_t meta_gstripe_get_type(void) +{ + return HR_METADATA_GEOM_STRIPE; +} + +static void meta_gstripe_dump(const void *md_v) +{ + HR_DEBUG("%s()", __func__); + + const struct g_stripe_metadata *md = md_v; + + printf(" magic: %s\n", md->md_magic); + printf(" version: %u\n", (u_int)md->md_version); + printf(" name: %s\n", md->md_name); + printf(" id: %u\n", (u_int)md->md_id); + printf(" no: %u\n", (u_int)md->md_no); + printf(" all: %u\n", (u_int)md->md_all); + printf("stripesize: %u\n", (u_int)md->md_stripesize); + printf(" mediasize: %jd\n", (intmax_t)md->md_provsize); +} + +static void *meta_gstripe_alloc_struct(void) +{ + return calloc(1, sizeof(struct g_stripe_metadata)); +} + +#if 0 static void meta_gstripe_encode(void *md_v, void *block) { HR_DEBUG("%s()", __func__); stripe_metadata_encode(md_v, block); } +#endif static errno_t meta_gstripe_decode(const void *block, void *md_v) { @@ -238,6 +353,7 @@ static errno_t meta_gstripe_get_block(service_id_t dev, void **rblock) return EOK; } +#if 0 static errno_t meta_gstripe_write_block(service_id_t dev, const void *block) { HR_DEBUG("%s()", __func__); @@ -264,6 +380,7 @@ static errno_t meta_gstripe_write_block(service_id_t dev, const void *block) return rc; } +#endif static bool meta_gstripe_has_valid_magic(const void *md_v) { @@ -277,87 +394,5 @@ static bool meta_gstripe_has_valid_magic(const void *md_v) return true; } -static bool meta_gstripe_compare_uuids(const void *md1_v, const void *md2_v) -{ - const struct g_stripe_metadata *md1 = md1_v; - const struct g_stripe_metadata *md2 = md2_v; - if (md1->md_id == md2->md_id) - return true; - - return false; -} - -static void meta_gstripe_inc_counter(hr_volume_t *vol) -{ - (void)vol; -} - -static errno_t meta_gstripe_save(hr_volume_t *vol, bool with_state_callback) -{ - HR_DEBUG("%s()", __func__); - - return ENOTSUP; -} - -static errno_t meta_gstripe_save_ext(hr_volume_t *vol, size_t ext_idx, - bool with_state_callback) -{ - HR_DEBUG("%s()", __func__); - - return ENOTSUP; -} - -static const char *meta_gstripe_get_devname(const void *md_v) -{ - const struct g_stripe_metadata *md = md_v; - - return md->md_name; -} - -static hr_level_t meta_gstripe_get_level(const void *md_v) -{ - (void)md_v; - - return HR_LVL_0; -} - -static uint64_t meta_gstripe_get_data_offset(void) -{ - return 0; -} - -static size_t meta_gstripe_get_size(void) -{ - return 1; -} - -static uint8_t meta_gstripe_get_flags(void) -{ - uint8_t flags = 0; - - return flags; -} - -static hr_metadata_type_t meta_gstripe_get_type(void) -{ - return HR_METADATA_GEOM_STRIPE; -} - -static void meta_gstripe_dump(const void *md_v) -{ - HR_DEBUG("%s()", __func__); - - const struct g_stripe_metadata *md = md_v; - - printf(" magic: %s\n", md->md_magic); - printf(" version: %u\n", (u_int)md->md_version); - printf(" name: %s\n", md->md_name); - printf(" id: %u\n", (u_int)md->md_id); - printf(" no: %u\n", (u_int)md->md_no); - printf(" all: %u\n", (u_int)md->md_all); - printf("stripesize: %u\n", (u_int)md->md_stripesize); - printf(" mediasize: %jd\n", (intmax_t)md->md_provsize); -} - /** @} */ diff --git a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c index 8a98cfd81a..54302a43b2 100644 --- a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c +++ b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c @@ -53,14 +53,17 @@ #include "softraidvar.h" +/* not exposed */ static void *meta_softraid_alloc_struct(void); -static errno_t meta_softraid_init_vol2meta(hr_volume_t *); -static errno_t meta_softraid_init_meta2vol(const list_t *, hr_volume_t *); -static void meta_softraid_encode(void *, void *); +/* static void meta_softraid_encode(void *, void *); */ static errno_t meta_softraid_decode(const void *, void *); static errno_t meta_softraid_get_block(service_id_t, void **); -static errno_t meta_softraid_write_block(service_id_t, const void *); +/* static errno_t meta_softraid_write_block(service_id_t, const void *); */ static bool meta_softraid_has_valid_magic(const void *); + +static errno_t meta_softraid_probe(service_id_t, void **); +static errno_t meta_softraid_init_vol2meta(hr_volume_t *); +static errno_t meta_softraid_init_meta2vol(const list_t *, hr_volume_t *); static bool meta_softraid_compare_uuids(const void *, const void *); static void meta_softraid_inc_counter(hr_volume_t *); static errno_t meta_softraid_save(hr_volume_t *, bool); @@ -74,14 +77,9 @@ static hr_metadata_type_t meta_softraid_get_type(void); static void meta_softraid_dump(const void *); hr_superblock_ops_t metadata_softraid_ops = { - .alloc_struct = meta_softraid_alloc_struct, + .probe = meta_softraid_probe, .init_vol2meta = meta_softraid_init_vol2meta, .init_meta2vol = meta_softraid_init_meta2vol, - .encode = meta_softraid_encode, - .decode = meta_softraid_decode, - .get_block = meta_softraid_get_block, - .write_block = meta_softraid_write_block, - .has_valid_magic = meta_softraid_has_valid_magic, .compare_uuids = meta_softraid_compare_uuids, .inc_counter = meta_softraid_inc_counter, .save = meta_softraid_save, @@ -95,9 +93,37 @@ hr_superblock_ops_t metadata_softraid_ops = { .dump = meta_softraid_dump }; -static void *meta_softraid_alloc_struct(void) +static errno_t meta_softraid_probe(service_id_t svc_id, void **rmd) { - return calloc(1, SR_META_SIZE * DEV_BSIZE); + errno_t rc; + void *meta_block; + + void *metadata_struct = meta_softraid_alloc_struct(); + if (metadata_struct == NULL) + return ENOMEM; + + rc = meta_softraid_get_block(svc_id, &meta_block); + if (rc != EOK) + goto error; + + rc = meta_softraid_decode(meta_block, metadata_struct); + + free(meta_block); + + if (rc != EOK) + goto error; + + if (!meta_softraid_has_valid_magic(metadata_struct)) { + rc = ENOFS; + goto error; + } + + *rmd = metadata_struct; + return EOK; + +error: + free(metadata_struct); + return ENOFS; } static errno_t meta_softraid_init_vol2meta(hr_volume_t *vol) @@ -180,6 +206,103 @@ static errno_t meta_softraid_init_meta2vol(const list_t *list, hr_volume_t *vol) return rc; } +static bool meta_softraid_compare_uuids(const void *m1_v, const void *m2_v) +{ + const struct sr_metadata *m1 = m1_v; + const struct sr_metadata *m2 = m2_v; + if (memcmp(&m1->ssdi.ssd_uuid, &m2->ssdi.ssd_uuid, + SR_UUID_MAX) == 0) + return true; + + return false; +} + +static void meta_softraid_inc_counter(hr_volume_t *vol) +{ + fibril_mutex_lock(&vol->md_lock); + + struct sr_metadata *md = vol->in_mem_md; + + md->ssd_ondisk++; + + fibril_mutex_unlock(&vol->md_lock); +} + +static errno_t meta_softraid_save(hr_volume_t *vol, bool with_state_callback) +{ + HR_DEBUG("%s()", __func__); + + return ENOTSUP; +} + +static errno_t meta_softraid_save_ext(hr_volume_t *vol, size_t ext_idx, + bool with_state_callback) +{ + HR_DEBUG("%s()", __func__); + + return ENOTSUP; +} + +static const char *meta_softraid_get_devname(const void *md_v) +{ + const struct sr_metadata *md = md_v; + + return md->ssd_devname; +} + +static hr_level_t meta_softraid_get_level(const void *md_v) +{ + const struct sr_metadata *md = md_v; + + switch (md->ssdi.ssd_level) { + case 0: + return HR_LVL_0; + case 1: + return HR_LVL_1; + case 5: + return HR_LVL_5; + default: + return HR_LVL_UNKNOWN; + } +} + +static uint64_t meta_softraid_get_data_offset(void) +{ + return SR_DATA_OFFSET; +} + +static size_t meta_softraid_get_size(void) +{ + return SR_META_SIZE; +} + +static uint8_t meta_softraid_get_flags(void) +{ + uint8_t flags = 0; + + return flags; +} + +static hr_metadata_type_t meta_softraid_get_type(void) +{ + return HR_METADATA_SOFTRAID; +} + +static void meta_softraid_dump(const void *md_v) +{ + HR_DEBUG("%s()", __func__); + + const struct sr_metadata *md = md_v; + + sr_meta_print(md); +} + +static void *meta_softraid_alloc_struct(void) +{ + return calloc(1, SR_META_SIZE * DEV_BSIZE); +} + +#if 0 static void meta_softraid_encode(void *md_v, void *block) { HR_DEBUG("%s()", __func__); @@ -187,6 +310,7 @@ static void meta_softraid_encode(void *md_v, void *block) (void)md_v; (void)block; } +#endif static errno_t meta_softraid_decode(const void *block, void *md_v) { @@ -371,6 +495,7 @@ static errno_t meta_softraid_get_block(service_id_t dev, void **rblock) return EOK; } +#if 0 static errno_t meta_softraid_write_block(service_id_t dev, const void *block) { HR_DEBUG("%s()", __func__); @@ -397,6 +522,7 @@ static errno_t meta_softraid_write_block(service_id_t dev, const void *block) return rc; } +#endif static bool meta_softraid_has_valid_magic(const void *md_v) { @@ -410,96 +536,5 @@ static bool meta_softraid_has_valid_magic(const void *md_v) return true; } -static bool meta_softraid_compare_uuids(const void *m1_v, const void *m2_v) -{ - const struct sr_metadata *m1 = m1_v; - const struct sr_metadata *m2 = m2_v; - if (memcmp(&m1->ssdi.ssd_uuid, &m2->ssdi.ssd_uuid, - SR_UUID_MAX) == 0) - return true; - - return false; -} - -static void meta_softraid_inc_counter(hr_volume_t *vol) -{ - fibril_mutex_lock(&vol->md_lock); - - struct sr_metadata *md = vol->in_mem_md; - - md->ssd_ondisk++; - - fibril_mutex_unlock(&vol->md_lock); -} - -static errno_t meta_softraid_save(hr_volume_t *vol, bool with_state_callback) -{ - HR_DEBUG("%s()", __func__); - - return ENOTSUP; -} - -static errno_t meta_softraid_save_ext(hr_volume_t *vol, size_t ext_idx, - bool with_state_callback) -{ - HR_DEBUG("%s()", __func__); - - return ENOTSUP; -} - -static const char *meta_softraid_get_devname(const void *md_v) -{ - const struct sr_metadata *md = md_v; - - return md->ssd_devname; -} - -static hr_level_t meta_softraid_get_level(const void *md_v) -{ - const struct sr_metadata *md = md_v; - - switch (md->ssdi.ssd_level) { - case 0: - return HR_LVL_0; - case 1: - return HR_LVL_1; - case 5: - return HR_LVL_5; - default: - return HR_LVL_UNKNOWN; - } -} - -static uint64_t meta_softraid_get_data_offset(void) -{ - return SR_DATA_OFFSET; -} - -static size_t meta_softraid_get_size(void) -{ - return SR_META_SIZE; -} - -static uint8_t meta_softraid_get_flags(void) -{ - uint8_t flags = 0; - - return flags; -} - -static hr_metadata_type_t meta_softraid_get_type(void) -{ - return HR_METADATA_SOFTRAID; -} - -static void meta_softraid_dump(const void *md_v) -{ - HR_DEBUG("%s()", __func__); - - const struct sr_metadata *md = md_v; - - sr_meta_print(md); -} - /** @} */ diff --git a/uspace/srv/bd/hr/metadata/native.c b/uspace/srv/bd/hr/metadata/native.c index 226613c402..15ff9fb759 100644 --- a/uspace/srv/bd/hr/metadata/native.c +++ b/uspace/srv/bd/hr/metadata/native.c @@ -53,15 +53,18 @@ #include "native.h" +/* not exposed */ static void *meta_native_alloc_struct(void); -static errno_t meta_native_init_vol2meta(hr_volume_t *); -static errno_t meta_native_init_meta2vol(const list_t *, hr_volume_t *); static void meta_native_encode(void *, void *); static errno_t meta_native_decode(const void *, void *); static errno_t meta_native_get_block(service_id_t, void **); static errno_t meta_native_write_block(service_id_t, const void *); -static errno_t meta_native_erase_block(service_id_t); static bool meta_native_has_valid_magic(const void *); + +static errno_t meta_native_probe(service_id_t, void **); +static errno_t meta_native_init_vol2meta(hr_volume_t *); +static errno_t meta_native_init_meta2vol(const list_t *, hr_volume_t *); +static errno_t meta_native_erase_block(service_id_t); static bool meta_native_compare_uuids(const void *, const void *); static void meta_native_inc_counter(hr_volume_t *); static errno_t meta_native_save(hr_volume_t *, bool); @@ -75,15 +78,10 @@ static hr_metadata_type_t meta_native_get_type(void); static void meta_native_dump(const void *); hr_superblock_ops_t metadata_native_ops = { - .alloc_struct = meta_native_alloc_struct, + .probe = meta_native_probe, .init_vol2meta = meta_native_init_vol2meta, .init_meta2vol = meta_native_init_meta2vol, - .encode = meta_native_encode, - .decode = meta_native_decode, - .get_block = meta_native_get_block, - .write_block = meta_native_write_block, .erase_block = meta_native_erase_block, - .has_valid_magic = meta_native_has_valid_magic, .compare_uuids = meta_native_compare_uuids, .inc_counter = meta_native_inc_counter, .save = meta_native_save, @@ -97,9 +95,37 @@ hr_superblock_ops_t metadata_native_ops = { .dump = meta_native_dump }; -static void *meta_native_alloc_struct(void) +static errno_t meta_native_probe(service_id_t svc_id, void **rmd) { - return calloc(1, sizeof(hr_metadata_t)); + errno_t rc; + void *meta_block; + + void *metadata_struct = meta_native_alloc_struct(); + if (metadata_struct == NULL) + return ENOMEM; + + rc = meta_native_get_block(svc_id, &meta_block); + if (rc != EOK) + goto error; + + rc = meta_native_decode(meta_block, metadata_struct); + + free(meta_block); + + if (rc != EOK) + goto error; + + if (!meta_native_has_valid_magic(metadata_struct)) { + rc = ENOFS; + goto error; + } + + *rmd = metadata_struct; + return EOK; + +error: + free(metadata_struct); + return ENOFS; } static errno_t meta_native_init_vol2meta(hr_volume_t *vol) @@ -201,146 +227,6 @@ static errno_t meta_native_init_meta2vol(const list_t *list, hr_volume_t *vol) return EOK; } -static void meta_native_encode(void *md_v, void *block) -{ - HR_DEBUG("%s()", __func__); - - const hr_metadata_t *metadata = md_v; - - /* - * Use scratch metadata for easier encoding without the need - * for manualy specifying offsets. - */ - hr_metadata_t scratch_md; - - memcpy(scratch_md.magic, metadata->magic, HR_NATIVE_MAGIC_SIZE); - memcpy(scratch_md.uuid, metadata->uuid, HR_NATIVE_UUID_LEN); - - scratch_md.data_blkno = host2uint64_t_le(metadata->data_blkno); - scratch_md.truncated_blkno = host2uint64_t_le( - metadata->truncated_blkno); - scratch_md.counter = host2uint64_t_le(metadata->counter); - scratch_md.rebuild_pos = host2uint64_t_le(metadata->rebuild_pos); - scratch_md.version = host2uint32_t_le(metadata->version); - scratch_md.extent_no = host2uint32_t_le(metadata->extent_no); - scratch_md.index = host2uint32_t_le(metadata->index); - scratch_md.level = host2uint32_t_le(metadata->level); - scratch_md.layout = host2uint32_t_le(metadata->layout); - scratch_md.strip_size = host2uint32_t_le(metadata->strip_size); - scratch_md.bsize = host2uint32_t_le(metadata->bsize); - memcpy(scratch_md.devname, metadata->devname, HR_DEVNAME_LEN); - - memcpy(block, &scratch_md, sizeof(hr_metadata_t)); -} - -static errno_t meta_native_decode(const void *block, void *md_v) -{ - HR_DEBUG("%s()", __func__); - - hr_metadata_t *metadata = md_v; - - /* - * Use scratch metadata for easier decoding without the need - * for manualy specifying offsets. - */ - hr_metadata_t scratch_md; - memcpy(&scratch_md, block, sizeof(hr_metadata_t)); - - memcpy(metadata->magic, scratch_md.magic, HR_NATIVE_MAGIC_SIZE); - memcpy(metadata->uuid, scratch_md.uuid, HR_NATIVE_UUID_LEN); - - metadata->data_blkno = uint64_t_le2host(scratch_md.data_blkno); - metadata->truncated_blkno = uint64_t_le2host( - scratch_md.truncated_blkno); - metadata->counter = uint64_t_le2host(scratch_md.counter); - metadata->rebuild_pos = uint64_t_le2host(scratch_md.rebuild_pos); - metadata->version = uint32_t_le2host(scratch_md.version); - metadata->extent_no = uint32_t_le2host(scratch_md.extent_no); - metadata->index = uint32_t_le2host(scratch_md.index); - metadata->level = uint32_t_le2host(scratch_md.level); - metadata->layout = uint32_t_le2host(scratch_md.layout); - metadata->strip_size = uint32_t_le2host(scratch_md.strip_size); - metadata->bsize = uint32_t_le2host(scratch_md.bsize); - memcpy(metadata->devname, scratch_md.devname, HR_DEVNAME_LEN); - - if (metadata->version != 1) - return EINVAL; - - return EOK; -} - -static errno_t meta_native_get_block(service_id_t dev, void **rblock) -{ - HR_DEBUG("%s()", __func__); - - errno_t rc; - uint64_t blkno; - size_t bsize; - void *block; - - if (rblock == NULL) - return EINVAL; - - rc = block_get_bsize(dev, &bsize); - if (rc != EOK) - return rc; - - if (bsize < sizeof(hr_metadata_t)) - return EINVAL; - - rc = block_get_nblocks(dev, &blkno); - if (rc != EOK) - return rc; - - if (blkno < HR_NATIVE_META_SIZE) - return EINVAL; - - block = malloc(bsize); - if (block == NULL) - return ENOMEM; - - rc = hr_read_direct(dev, blkno - 1, HR_NATIVE_META_SIZE, block); - /* - * XXX: here maybe call vol state event or the state callback... - * - * but need to pass vol pointer - */ - if (rc != EOK) { - free(block); - return rc; - } - - *rblock = block; - return EOK; -} - -static errno_t meta_native_write_block(service_id_t dev, const void *block) -{ - HR_DEBUG("%s()", __func__); - - errno_t rc; - uint64_t blkno; - size_t bsize; - - rc = block_get_bsize(dev, &bsize); - if (rc != EOK) - return rc; - - if (bsize < sizeof(hr_metadata_t)) - return EINVAL; - - rc = block_get_nblocks(dev, &blkno); - if (rc != EOK) - return rc; - - if (blkno < HR_NATIVE_META_SIZE) - return EINVAL; - - rc = hr_write_direct(dev, blkno - 1, HR_NATIVE_META_SIZE, block); - - return rc; -} - static errno_t meta_native_erase_block(service_id_t dev) { HR_DEBUG("%s()", __func__); @@ -360,18 +246,6 @@ static errno_t meta_native_erase_block(service_id_t dev) return rc; } -static bool meta_native_has_valid_magic(const void *md_v) -{ - HR_DEBUG("%s()", __func__); - - const hr_metadata_t *md = md_v; - - if (str_lcmp(md->magic, HR_NATIVE_MAGIC_STR, HR_NATIVE_MAGIC_SIZE) != 0) - return false; - - return true; -} - static bool meta_native_compare_uuids(const void *m1p, const void *m2p) { const hr_metadata_t *m1 = m1p; @@ -514,5 +388,162 @@ static void meta_native_dump(const void *md_v) printf("\tdevname: %s\n", metadata->devname); } +static void *meta_native_alloc_struct(void) +{ + return calloc(1, sizeof(hr_metadata_t)); +} + +static void meta_native_encode(void *md_v, void *block) +{ + HR_DEBUG("%s()", __func__); + + const hr_metadata_t *metadata = md_v; + + /* + * Use scratch metadata for easier encoding without the need + * for manualy specifying offsets. + */ + hr_metadata_t scratch_md; + + memcpy(scratch_md.magic, metadata->magic, HR_NATIVE_MAGIC_SIZE); + memcpy(scratch_md.uuid, metadata->uuid, HR_NATIVE_UUID_LEN); + + scratch_md.data_blkno = host2uint64_t_le(metadata->data_blkno); + scratch_md.truncated_blkno = host2uint64_t_le( + metadata->truncated_blkno); + scratch_md.counter = host2uint64_t_le(metadata->counter); + scratch_md.rebuild_pos = host2uint64_t_le(metadata->rebuild_pos); + scratch_md.version = host2uint32_t_le(metadata->version); + scratch_md.extent_no = host2uint32_t_le(metadata->extent_no); + scratch_md.index = host2uint32_t_le(metadata->index); + scratch_md.level = host2uint32_t_le(metadata->level); + scratch_md.layout = host2uint32_t_le(metadata->layout); + scratch_md.strip_size = host2uint32_t_le(metadata->strip_size); + scratch_md.bsize = host2uint32_t_le(metadata->bsize); + memcpy(scratch_md.devname, metadata->devname, HR_DEVNAME_LEN); + + memcpy(block, &scratch_md, sizeof(hr_metadata_t)); +} + +static errno_t meta_native_decode(const void *block, void *md_v) +{ + HR_DEBUG("%s()", __func__); + + hr_metadata_t *metadata = md_v; + + /* + * Use scratch metadata for easier decoding without the need + * for manualy specifying offsets. + */ + hr_metadata_t scratch_md; + memcpy(&scratch_md, block, sizeof(hr_metadata_t)); + + memcpy(metadata->magic, scratch_md.magic, HR_NATIVE_MAGIC_SIZE); + memcpy(metadata->uuid, scratch_md.uuid, HR_NATIVE_UUID_LEN); + + metadata->data_blkno = uint64_t_le2host(scratch_md.data_blkno); + metadata->truncated_blkno = uint64_t_le2host( + scratch_md.truncated_blkno); + metadata->counter = uint64_t_le2host(scratch_md.counter); + metadata->rebuild_pos = uint64_t_le2host(scratch_md.rebuild_pos); + metadata->version = uint32_t_le2host(scratch_md.version); + metadata->extent_no = uint32_t_le2host(scratch_md.extent_no); + metadata->index = uint32_t_le2host(scratch_md.index); + metadata->level = uint32_t_le2host(scratch_md.level); + metadata->layout = uint32_t_le2host(scratch_md.layout); + metadata->strip_size = uint32_t_le2host(scratch_md.strip_size); + metadata->bsize = uint32_t_le2host(scratch_md.bsize); + memcpy(metadata->devname, scratch_md.devname, HR_DEVNAME_LEN); + + if (metadata->version != 1) + return EINVAL; + + return EOK; +} + +static errno_t meta_native_get_block(service_id_t dev, void **rblock) +{ + HR_DEBUG("%s()", __func__); + + errno_t rc; + uint64_t blkno; + size_t bsize; + void *block; + + if (rblock == NULL) + return EINVAL; + + rc = block_get_bsize(dev, &bsize); + if (rc != EOK) + return rc; + + if (bsize < sizeof(hr_metadata_t)) + return EINVAL; + + rc = block_get_nblocks(dev, &blkno); + if (rc != EOK) + return rc; + + if (blkno < HR_NATIVE_META_SIZE) + return EINVAL; + + block = malloc(bsize); + if (block == NULL) + return ENOMEM; + + rc = hr_read_direct(dev, blkno - 1, HR_NATIVE_META_SIZE, block); + /* + * XXX: here maybe call vol state event or the state callback... + * + * but need to pass vol pointer + */ + if (rc != EOK) { + free(block); + return rc; + } + + *rblock = block; + return EOK; +} + +static errno_t meta_native_write_block(service_id_t dev, const void *block) +{ + HR_DEBUG("%s()", __func__); + + errno_t rc; + uint64_t blkno; + size_t bsize; + + rc = block_get_bsize(dev, &bsize); + if (rc != EOK) + return rc; + + if (bsize < sizeof(hr_metadata_t)) + return EINVAL; + + rc = block_get_nblocks(dev, &blkno); + if (rc != EOK) + return rc; + + if (blkno < HR_NATIVE_META_SIZE) + return EINVAL; + + rc = hr_write_direct(dev, blkno - 1, HR_NATIVE_META_SIZE, block); + + return rc; +} + +static bool meta_native_has_valid_magic(const void *md_v) +{ + HR_DEBUG("%s()", __func__); + + const hr_metadata_t *md = md_v; + + if (str_lcmp(md->magic, HR_NATIVE_MAGIC_STR, HR_NATIVE_MAGIC_SIZE) != 0) + return false; + + return true; +} + /** @} */ diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index 4b1a7c4aa6..548f340859 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -67,21 +67,20 @@ static hr_superblock_ops_t *hr_superblock_ops_all[] = { [HR_METADATA_SOFTRAID] = &metadata_softraid_ops }; -hr_superblock_ops_t *get_type_ops(hr_metadata_type_t type) +hr_superblock_ops_t *hr_get_meta_type_ops(hr_metadata_type_t type) { assert(type >= HR_METADATA_NATIVE && type < HR_METADATA_LAST_DUMMY); return hr_superblock_ops_all[type]; } -errno_t find_metadata(service_id_t svc_id, void **rmetadata, +errno_t hr_find_metadata(service_id_t svc_id, void **rmetadata, hr_metadata_type_t *rtype) { HR_DEBUG("%s()", __func__); errno_t rc; hr_superblock_ops_t *meta_ops; - void *meta_block; void *metadata_struct; if (rmetadata == NULL) @@ -93,30 +92,10 @@ errno_t find_metadata(service_id_t svc_id, void **rmetadata, for (; type < HR_METADATA_LAST_DUMMY; type++) { meta_ops = hr_superblock_ops_all[type]; - metadata_struct = meta_ops->alloc_struct(); - if (metadata_struct == NULL) - return ENOMEM; - - rc = meta_ops->get_block(svc_id, &meta_block); - if (rc == ENOMEM) { - free(metadata_struct); - return ENOMEM; - } else if (rc != EOK) { - free(metadata_struct); - continue; - } - - rc = meta_ops->decode(meta_block, metadata_struct); - - free(meta_block); - + rc = meta_ops->probe(svc_id, &metadata_struct); if (rc != EOK) { - free(metadata_struct); - continue; - } - - if (!meta_ops->has_valid_magic(metadata_struct)) { - free(metadata_struct); + if (rc != ENOFS) + return rc; continue; } diff --git a/uspace/srv/bd/hr/superblock.h b/uspace/srv/bd/hr/superblock.h index 034a9e44f3..5d2addd20e 100644 --- a/uspace/srv/bd/hr/superblock.h +++ b/uspace/srv/bd/hr/superblock.h @@ -43,15 +43,10 @@ typedef struct hr_volume hr_volume_t; #define HR_METADATA_HOTSPARE_SUPPORT 0x01 typedef struct hr_superblock_ops { - void *(*alloc_struct)(void); + errno_t (*probe)(service_id_t, void **); errno_t (*init_vol2meta)(hr_volume_t *); errno_t (*init_meta2vol)(const list_t *, hr_volume_t *); - void (*encode)(void *, void *); - errno_t (*decode)(const void *, void *); - errno_t (*get_block)(service_id_t, void **); - errno_t (*write_block)(service_id_t, const void *); errno_t (*erase_block)(service_id_t); - bool (*has_valid_magic)(const void *); bool (*compare_uuids)(const void *, const void *); void (*inc_counter)(hr_volume_t *); errno_t (*save)(hr_volume_t *, bool); @@ -65,8 +60,8 @@ typedef struct hr_superblock_ops { hr_metadata_type_t (*get_type)(void); } hr_superblock_ops_t; -extern hr_superblock_ops_t *get_type_ops(hr_metadata_type_t); -extern errno_t find_metadata(service_id_t, void **, hr_metadata_type_t *); +extern hr_superblock_ops_t *hr_get_meta_type_ops(hr_metadata_type_t); +extern errno_t hr_find_metadata(service_id_t, void **, hr_metadata_type_t *); #endif diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index c44e16e8c7..47f29a9812 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -114,7 +114,7 @@ errno_t hr_create_vol_struct(hr_volume_t **rvol, hr_level_t level, str_cpy(vol->devname, HR_DEVNAME_LEN, devname); vol->level = level; - vol->meta_ops = get_type_ops(metadata_type); + vol->meta_ops = hr_get_meta_type_ops(metadata_type); uint8_t meta_flags = vol->meta_ops->get_flags(); @@ -791,7 +791,7 @@ static errno_t hr_util_get_matching_md_svcs_list(list_t *rlist, list_t *list, errno_t rc = EOK; - hr_superblock_ops_t *meta_ops = get_type_ops(type_main); + hr_superblock_ops_t *meta_ops = hr_get_meta_type_ops(type_main); list_foreach(*list, link, struct dev_list_member, iter) { if (iter->svc_id == svc_id) @@ -800,7 +800,7 @@ static errno_t hr_util_get_matching_md_svcs_list(list_t *rlist, list_t *list, void *metadata_struct; hr_metadata_type_t type; - rc = find_metadata(iter->svc_id, &metadata_struct, &type); + rc = hr_find_metadata(iter->svc_id, &metadata_struct, &type); if (rc == ENOFS) continue; if (rc != EOK) @@ -836,7 +836,7 @@ static errno_t hr_util_assemble_from_matching_list(list_t *list, errno_t rc = EOK; - hr_superblock_ops_t *meta_ops = get_type_ops(type); + hr_superblock_ops_t *meta_ops = hr_get_meta_type_ops(type); link_t *memb_l = list_first(list); struct dev_list_member *memb = list_get_instance(memb_l, @@ -932,7 +932,7 @@ errno_t hr_util_try_assemble(hr_config_t *cfg, size_t *rassembled_cnt) void *metadata_struct_main; hr_metadata_type_t type; - rc = find_metadata(iter->svc_id, &metadata_struct_main, &type); + rc = hr_find_metadata(iter->svc_id, &metadata_struct_main, &type); if (rc == ENOFS) { block_fini(iter->svc_id); free_dev_list_member(iter); From 2de7c1f42832a758c43a26c5f55015317a282d6d Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sat, 28 Jun 2025 00:27:26 +0200 Subject: [PATCH 282/324] hr: metadata/foreign: implement erase_block() It is safer for foreign metadata to return ENOTSUP. --- uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c | 11 +++++++++++ uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c | 11 +++++++++++ .../srv/bd/hr/metadata/foreign/softraid/hr_softraid.c | 11 +++++++++++ 3 files changed, 33 insertions(+) diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c index 6d1bd7baed..7f81a7c795 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c @@ -64,6 +64,7 @@ static bool meta_gmirror_has_valid_magic(const void *); static errno_t meta_gmirror_probe(service_id_t, void **); static errno_t meta_gmirror_init_vol2meta(hr_volume_t *); static errno_t meta_gmirror_init_meta2vol(const list_t *, hr_volume_t *); +static errno_t meta_gmirror_erase_block(service_id_t); static bool meta_gmirror_compare_uuids(const void *, const void *); static void meta_gmirror_inc_counter(hr_volume_t *); static errno_t meta_gmirror_save(hr_volume_t *, bool); @@ -80,6 +81,7 @@ hr_superblock_ops_t metadata_gmirror_ops = { .probe = meta_gmirror_probe, .init_vol2meta = meta_gmirror_init_vol2meta, .init_meta2vol = meta_gmirror_init_meta2vol, + .erase_block = meta_gmirror_erase_block, .compare_uuids = meta_gmirror_compare_uuids, .inc_counter = meta_gmirror_inc_counter, .save = meta_gmirror_save, @@ -202,6 +204,15 @@ static errno_t meta_gmirror_init_meta2vol(const list_t *list, hr_volume_t *vol) return rc; } +static errno_t meta_gmirror_erase_block(service_id_t dev) +{ + HR_DEBUG("%s()", __func__); + + (void)dev; + + return ENOTSUP; +} + static bool meta_gmirror_compare_uuids(const void *m1_v, const void *m2_v) { const struct g_mirror_metadata *m1 = m1_v; diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c index df2687eca3..5131f8b21f 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c @@ -64,6 +64,7 @@ static bool meta_gstripe_has_valid_magic(const void *); static errno_t meta_gstripe_probe(service_id_t, void **); static errno_t meta_gstripe_init_vol2meta(hr_volume_t *); static errno_t meta_gstripe_init_meta2vol(const list_t *, hr_volume_t *); +static errno_t meta_gstripe_erase_block(service_id_t); static bool meta_gstripe_compare_uuids(const void *, const void *); static void meta_gstripe_inc_counter(hr_volume_t *); static errno_t meta_gstripe_save(hr_volume_t *, bool); @@ -80,6 +81,7 @@ hr_superblock_ops_t metadata_gstripe_ops = { .probe = meta_gstripe_probe, .init_vol2meta = meta_gstripe_init_vol2meta, .init_meta2vol = meta_gstripe_init_meta2vol, + .erase_block = meta_gstripe_erase_block, .compare_uuids = meta_gstripe_compare_uuids, .inc_counter = meta_gstripe_inc_counter, .save = meta_gstripe_save, @@ -203,6 +205,15 @@ static errno_t meta_gstripe_init_meta2vol(const list_t *list, hr_volume_t *vol) return rc; } +static errno_t meta_gstripe_erase_block(service_id_t dev) +{ + HR_DEBUG("%s()", __func__); + + (void)dev; + + return ENOTSUP; +} + static bool meta_gstripe_compare_uuids(const void *md1_v, const void *md2_v) { const struct g_stripe_metadata *md1 = md1_v; diff --git a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c index 54302a43b2..50d1c3afd6 100644 --- a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c +++ b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c @@ -64,6 +64,7 @@ static bool meta_softraid_has_valid_magic(const void *); static errno_t meta_softraid_probe(service_id_t, void **); static errno_t meta_softraid_init_vol2meta(hr_volume_t *); static errno_t meta_softraid_init_meta2vol(const list_t *, hr_volume_t *); +static errno_t meta_softraid_erase_block(service_id_t); static bool meta_softraid_compare_uuids(const void *, const void *); static void meta_softraid_inc_counter(hr_volume_t *); static errno_t meta_softraid_save(hr_volume_t *, bool); @@ -80,6 +81,7 @@ hr_superblock_ops_t metadata_softraid_ops = { .probe = meta_softraid_probe, .init_vol2meta = meta_softraid_init_vol2meta, .init_meta2vol = meta_softraid_init_meta2vol, + .erase_block = meta_softraid_erase_block, .compare_uuids = meta_softraid_compare_uuids, .inc_counter = meta_softraid_inc_counter, .save = meta_softraid_save, @@ -206,6 +208,15 @@ static errno_t meta_softraid_init_meta2vol(const list_t *list, hr_volume_t *vol) return rc; } +static errno_t meta_softraid_erase_block(service_id_t dev) +{ + HR_DEBUG("%s()", __func__); + + (void)dev; + + return ENOTSUP; +} + static bool meta_softraid_compare_uuids(const void *m1_v, const void *m2_v) { const struct sr_metadata *m1 = m1_v; From f93b8869b5d428bc14924ef520d09b4aa3efa60e Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sat, 28 Jun 2025 15:14:00 +0200 Subject: [PATCH 283/324] hrctl: use single quotes for volume name Also put ' ' before byte SI. --- uspace/app/hrctl/hrctl.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index 1fb597d63c..498b7ad8ad 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -640,7 +640,7 @@ static errno_t print_vol_info(hr_vol_info_t *info) hr_extent_t *ext; const char *devname; - printf("volume: \"%s\" (%" PRIun ")\n", info->devname, info->svc_id); + printf("volume: '%s' (%" PRIun ")\n", info->devname, info->svc_id); printf("| metadata type: %s\n", hr_get_metadata_type_str(info->meta_type)); @@ -651,10 +651,10 @@ static errno_t print_vol_info(hr_vol_info_t *info) if (info->strip_size > 0) { if (info->strip_size < 1024) { - printf("| strip size: %" PRIu32 "B\n", + printf("| strip size: %" PRIu32 " B\n", info->strip_size); } else { - printf("| strip size: %" PRIu32 "KiB\n", + printf("| strip size: %" PRIu32 " KiB\n", info->strip_size / 1024); } } @@ -662,7 +662,7 @@ static errno_t print_vol_info(hr_vol_info_t *info) printf("| no. of extents: %zu\n", info->extent_no); printf("|no. of hotspares: %zu\n", info->hotspare_no); printf("|number of blocks: %" PRIu64 "\n", info->data_blkno); - printf("| block size: %zuB\n", info->bsize); + printf("| block size: %zu B\n", info->bsize); capa_spec_t capa; char *scapa = NULL; @@ -762,7 +762,7 @@ static int handle_state(hr_t *hr, int argc, char **argv) "%s\n", str_error(rc)); return EXIT_FAILURE; } - printf("volume \"%s\" (%" PRIun ") %s\n", devname, + printf("volume '%s' (%" PRIun ") %s\n", devname, svc_id, hr_get_vol_state_str(state)); free(devname); From 8ad48d1c879a8e43f5eddffad94f574a5fffc43b Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sat, 28 Jun 2025 15:15:16 +0200 Subject: [PATCH 284/324] hr: metadata/gmirror: use syncid as on-disk counter --- uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c index 7f81a7c795..0fdca50372 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c @@ -147,8 +147,8 @@ static errno_t meta_gmirror_init_meta2vol(const list_t *list, hr_volume_t *vol) list_foreach(*list, link, struct dev_list_member, iter) { struct g_mirror_metadata *iter_meta = iter->md; - if (iter_meta->md_genid >= max_counter_val) { - max_counter_val = iter_meta->md_genid; + if (iter_meta->md_syncid >= max_counter_val) { + max_counter_val = iter_meta->md_syncid; main_meta = iter_meta; } } @@ -187,7 +187,7 @@ static errno_t meta_gmirror_init_meta2vol(const list_t *list, hr_volume_t *vol) iter->fini = false; /* for now no md_sync_offset handling for saved REBUILD */ - if (iter_meta->md_genid == max_counter_val) + if (iter_meta->md_syncid == max_counter_val) vol->extents[index].state = HR_EXT_ONLINE; else vol->extents[index].state = HR_EXT_INVALID; @@ -229,8 +229,7 @@ static void meta_gmirror_inc_counter(hr_volume_t *vol) struct g_mirror_metadata *md = vol->in_mem_md; - /* XXX: probably md_genid and not md_syncid is incremented */ - md->md_genid++; + md->md_syncid++; fibril_mutex_unlock(&vol->md_lock); } From aaf741ff297c52b299e30bf30b37ec6ea32c8ec9 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sat, 28 Jun 2025 17:07:17 +0200 Subject: [PATCH 285/324] hr: metadata/foreign: alloc metadata structs --- uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c | 3 +++ uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c | 3 +++ uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c | 3 +++ 3 files changed, 9 insertions(+) diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c index 0fdca50372..b978ce6f28 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c @@ -177,6 +177,9 @@ static errno_t meta_gmirror_init_meta2vol(const list_t *list, hr_volume_t *vol) vol->bsize = main_meta->md_sectorsize; + vol->in_mem_md = calloc(1, sizeof(struct g_mirror_metadata)); + if (vol->in_mem_md == NULL) + return ENOMEM; memcpy(vol->in_mem_md, main_meta, sizeof(struct g_mirror_metadata)); uint8_t index = 0; diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c index 5131f8b21f..7c7e099af1 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c @@ -184,6 +184,9 @@ static errno_t meta_gstripe_init_meta2vol(const list_t *list, hr_volume_t *vol) vol->layout = HR_LAYOUT_NONE; + vol->in_mem_md = calloc(1, sizeof(struct g_stripe_metadata)); + if (vol->in_mem_md == NULL) + return ENOMEM; memcpy(vol->in_mem_md, main_meta, sizeof(struct g_stripe_metadata)); list_foreach(*list, link, struct dev_list_member, iter) { diff --git a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c index 50d1c3afd6..ec913f5e7a 100644 --- a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c +++ b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c @@ -182,6 +182,9 @@ static errno_t meta_softraid_init_meta2vol(const list_t *list, hr_volume_t *vol) vol->strip_size = main_meta->ssdi.ssd_strip_size; + vol->in_mem_md = calloc(1, SR_META_SIZE * DEV_BSIZE); + if (vol->in_mem_md == NULL) + return ENOMEM; memcpy(vol->in_mem_md, main_meta, SR_META_SIZE * DEV_BSIZE); list_foreach(*list, link, struct dev_list_member, iter) { From d220b7dc715e474c7f45cca013cfad7877f4edab Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sat, 28 Jun 2025 20:04:36 +0200 Subject: [PATCH 286/324] hr: change HelenRAID native metadata type str --- uspace/lib/device/src/hr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index 81ed03715d..0c43f6af33 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -544,7 +544,7 @@ const char *hr_get_metadata_type_str(hr_metadata_type_t type) { switch (type) { case HR_METADATA_NATIVE: - return "Native HelenRAID metadata"; + return "HelenRAID native"; case HR_METADATA_GEOM_MIRROR: return "GEOM::MIRROR"; case HR_METADATA_GEOM_STRIPE: From c24f96bfd5815ef72c707f22c1f8d73858992d2f Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sat, 28 Jun 2025 20:04:56 +0200 Subject: [PATCH 287/324] hr: add OpenBSD softraid metadata type str --- uspace/lib/device/src/hr.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index 0c43f6af33..18c99a1e39 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -549,6 +549,8 @@ const char *hr_get_metadata_type_str(hr_metadata_type_t type) return "GEOM::MIRROR"; case HR_METADATA_GEOM_STRIPE: return "GEOM::STRIPE"; + case HR_METADATA_SOFTRAID: + return "OpenBSD softraid"; default: return "Invalid metadata type value"; } From 2192a0192709982436a1529729367fecf547e3ea Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 29 Jun 2025 00:34:44 +0200 Subject: [PATCH 288/324] hr: basic Linux Multiple Device RAID format support --- uspace/lib/device/include/hr.h | 1 + uspace/lib/device/src/hr.c | 2 + uspace/srv/bd/hr/meson.build | 1 + uspace/srv/bd/hr/metadata/foreign/md/hr_md.c | 625 +++++++++++++++++++ uspace/srv/bd/hr/metadata/foreign/md/md_p.h | 140 +++++ uspace/srv/bd/hr/superblock.c | 4 +- 6 files changed, 772 insertions(+), 1 deletion(-) create mode 100644 uspace/srv/bd/hr/metadata/foreign/md/hr_md.c create mode 100644 uspace/srv/bd/hr/metadata/foreign/md/md_p.h diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index d27b39fa78..f5c06c1b5d 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -86,6 +86,7 @@ typedef enum { HR_METADATA_GEOM_MIRROR, HR_METADATA_GEOM_STRIPE, HR_METADATA_SOFTRAID, + HR_METADATA_MD, HR_METADATA_LAST_DUMMY } hr_metadata_type_t; diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index 18c99a1e39..489818292f 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -551,6 +551,8 @@ const char *hr_get_metadata_type_str(hr_metadata_type_t type) return "GEOM::STRIPE"; case HR_METADATA_SOFTRAID: return "OpenBSD softraid"; + case HR_METADATA_MD: + return "Linux Multiple Device"; default: return "Invalid metadata type value"; } diff --git a/uspace/srv/bd/hr/meson.build b/uspace/srv/bd/hr/meson.build index 85ee18f68f..d30437e0db 100644 --- a/uspace/srv/bd/hr/meson.build +++ b/uspace/srv/bd/hr/meson.build @@ -33,6 +33,7 @@ src = files( 'io.c', 'metadata/foreign/geom/hr_g_mirror.c', 'metadata/foreign/geom/hr_g_stripe.c', + 'metadata/foreign/md/hr_md.c', 'metadata/foreign/softraid/hr_softraid.c', 'metadata/foreign/softraid/softraid.c', 'metadata/native.c', diff --git a/uspace/srv/bd/hr/metadata/foreign/md/hr_md.c b/uspace/srv/bd/hr/metadata/foreign/md/hr_md.c new file mode 100644 index 0000000000..49c94c8244 --- /dev/null +++ b/uspace/srv/bd/hr/metadata/foreign/md/hr_md.c @@ -0,0 +1,625 @@ +/* + * 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 +#include +#include +#include + +#include "../../../io.h" +#include "../../../util.h" +#include "../../../var.h" + +#include "md_p.h" + +/* not exposed */ +static void *meta_md_alloc_struct(void); +/* static void meta_md_encode(void *, void *); */ +static errno_t meta_md_decode(const void *, void *); +static errno_t meta_md_get_block(service_id_t, void **); +/* static errno_t meta_md_write_block(service_id_t, const void *); */ +static bool meta_md_has_valid_magic(const void *); + +static errno_t meta_md_probe(service_id_t, void **); +static errno_t meta_md_init_vol2meta(hr_volume_t *); +static errno_t meta_md_init_meta2vol(const list_t *, hr_volume_t *); +static errno_t meta_md_erase_block(service_id_t); +static bool meta_md_compare_uuids(const void *, const void *); +static void meta_md_inc_counter(hr_volume_t *); +static errno_t meta_md_save(hr_volume_t *, bool); +static errno_t meta_md_save_ext(hr_volume_t *, size_t, bool); +static const char *meta_md_get_devname(const void *); +static hr_level_t meta_md_get_level(const void *); +static uint64_t meta_md_get_data_offset(void); +static size_t meta_md_get_size(void); +static uint8_t meta_md_get_flags(void); +static hr_metadata_type_t meta_md_get_type(void); +static void meta_md_dump(const void *); + +hr_superblock_ops_t metadata_md_ops = { + .probe = meta_md_probe, + .init_vol2meta = meta_md_init_vol2meta, + .init_meta2vol = meta_md_init_meta2vol, + .erase_block = meta_md_erase_block, + .compare_uuids = meta_md_compare_uuids, + .inc_counter = meta_md_inc_counter, + .save = meta_md_save, + .save_ext = meta_md_save_ext, + .get_devname = meta_md_get_devname, + .get_level = meta_md_get_level, + .get_data_offset = meta_md_get_data_offset, + .get_size = meta_md_get_size, + .get_flags = meta_md_get_flags, + .get_type = meta_md_get_type, + .dump = meta_md_dump +}; + +static errno_t meta_md_probe(service_id_t svc_id, void **rmd) +{ + errno_t rc; + void *meta_block; + + void *metadata_struct = meta_md_alloc_struct(); + if (metadata_struct == NULL) + return ENOMEM; + + rc = meta_md_get_block(svc_id, &meta_block); + if (rc != EOK) + goto error; + + rc = meta_md_decode(meta_block, metadata_struct); + + free(meta_block); + + if (rc != EOK) + goto error; + + if (!meta_md_has_valid_magic(metadata_struct)) { + rc = ENOFS; + goto error; + } + + *rmd = metadata_struct; + return EOK; + +error: + free(metadata_struct); + return ENOFS; +} + +static errno_t meta_md_init_vol2meta(hr_volume_t *vol) +{ + (void)vol; + + return ENOTSUP; +} + +static errno_t meta_md_init_meta2vol(const list_t *list, hr_volume_t *vol) +{ + HR_DEBUG("%s()", __func__); + + errno_t rc = EOK; + + struct mdp_superblock_1 *main_meta = NULL; + uint64_t max_events = 0; + + list_foreach(*list, link, struct dev_list_member, iter) { + struct mdp_superblock_1 *iter_meta = iter->md; + + if (iter_meta->events >= max_events) { + max_events = iter_meta->events; + main_meta = iter_meta; + } + } + + assert(main_meta != NULL); + + vol->bsize = 512; + + vol->truncated_blkno = main_meta->size; + + vol->extent_no = main_meta->raid_disks; + + switch (vol->level) { + case HR_LVL_0: + vol->data_blkno = vol->truncated_blkno * vol->extent_no; + vol->layout = HR_LAYOUT_NONE; + break; + case HR_LVL_1: + vol->data_blkno = vol->truncated_blkno; + vol->layout = HR_LAYOUT_NONE; + break; + case HR_LVL_4: + vol->data_blkno = vol->truncated_blkno * (vol->extent_no - 1); + vol->layout = HR_LAYOUT_RAID4_N; + break; + case HR_LVL_5: + vol->data_blkno = vol->truncated_blkno * (vol->extent_no - 1); + switch (main_meta->layout) { + case ALGORITHM_LEFT_ASYMMETRIC: + vol->layout = HR_LAYOUT_RAID5_NR; + break; + case ALGORITHM_RIGHT_ASYMMETRIC: + vol->layout = HR_LAYOUT_RAID5_0R; + break; + case ALGORITHM_LEFT_SYMMETRIC: + vol->layout = HR_LAYOUT_RAID5_NC; + break; + } + break; + default: + return EINVAL; + } + + vol->data_offset = main_meta->data_offset; + + vol->strip_size = main_meta->chunksize * 512; + + vol->in_mem_md = calloc(1, MD_SIZE * 512); + if (vol->in_mem_md == NULL) + return ENOMEM; + memcpy(vol->in_mem_md, main_meta, MD_SIZE * 512); + + list_foreach(*list, link, struct dev_list_member, iter) { + struct mdp_superblock_1 *iter_meta = iter->md; + + uint8_t index = iter_meta->dev_roles[iter_meta->dev_number]; + + vol->extents[index].svc_id = iter->svc_id; + iter->fini = false; + + if (iter_meta->events == max_events && index < vol->extent_no) + vol->extents[index].state = HR_EXT_ONLINE; + else + vol->extents[index].state = HR_EXT_INVALID; + } + + for (size_t i = 0; i < vol->extent_no; i++) { + if (vol->extents[i].state == HR_EXT_NONE) + vol->extents[i].state = HR_EXT_MISSING; + } + + return rc; +} + +static errno_t meta_md_erase_block(service_id_t dev) +{ + HR_DEBUG("%s()", __func__); + + (void)dev; + + return ENOTSUP; +} + +static bool meta_md_compare_uuids(const void *m1_v, const void *m2_v) +{ + const struct mdp_superblock_1 *m1 = m1_v; + const struct mdp_superblock_1 *m2 = m2_v; + if (memcmp(&m1->set_uuid, &m2->set_uuid, 16) == 0) + return true; + + return false; +} + +static void meta_md_inc_counter(hr_volume_t *vol) +{ + fibril_mutex_lock(&vol->md_lock); + + struct mdp_superblock_1 *md = vol->in_mem_md; + + md->events++; + + fibril_mutex_unlock(&vol->md_lock); +} + +static errno_t meta_md_save(hr_volume_t *vol, bool with_state_callback) +{ + HR_DEBUG("%s()", __func__); + + return ENOTSUP; +} + +static errno_t meta_md_save_ext(hr_volume_t *vol, size_t ext_idx, + bool with_state_callback) +{ + HR_DEBUG("%s()", __func__); + + return ENOTSUP; +} + +static const char *meta_md_get_devname(const void *md_v) +{ + const struct mdp_superblock_1 *md = md_v; + + return md->set_name; +} + +static hr_level_t meta_md_get_level(const void *md_v) +{ + const struct mdp_superblock_1 *md = md_v; + + switch (md->level) { + case 0: + return HR_LVL_0; + case 1: + return HR_LVL_1; + case 4: + return HR_LVL_4; + case 5: + return HR_LVL_5; + default: + return HR_LVL_UNKNOWN; + } +} + +static uint64_t meta_md_get_data_offset(void) +{ + return MD_DATA_OFFSET; +} + +static size_t meta_md_get_size(void) +{ + return MD_SIZE; +} + +static uint8_t meta_md_get_flags(void) +{ + uint8_t flags = 0; + + return flags; +} + +static hr_metadata_type_t meta_md_get_type(void) +{ + return HR_METADATA_MD; +} + +static void bytefield_print(const uint8_t *d, size_t s) +{ + size_t i; + + for (i = 0; i < s; i++) + printf("%02x", d[i]); +} + +static void meta_md_dump(const void *md_v) +{ + HR_DEBUG("%s()", __func__); + + const struct mdp_superblock_1 *md = md_v; + + printf("magic: 0x%" PRIx32 "\n", md->magic); + + printf("major_version: %" PRIu32 "\n", md->major_version); + + printf("feature_map: 0x%" PRIx32 "\n", md->feature_map); + + printf("set_uuid: "); + bytefield_print(md->set_uuid, 16); + printf("\n"); + + printf("set_name: %s\n", md->set_name); + + printf("level: %" PRIi32 "\n", md->level); + + printf("layout: %" PRIi32 "\n", md->layout); + + printf("size: %" PRIu64 "\n", md->size); + + printf("chunksize: %" PRIu32 "\n", md->chunksize); + + printf("raid_disks: %" PRIu32 "\n", md->raid_disks); + + printf("data_offset: %" PRIu64 "\n", md->data_offset); + + printf("data_size: %" PRIu64 "\n", md->data_size); + + printf("super_offset: %" PRIu64 "\n", md->super_offset); + + printf("dev_number: %" PRIu32 "\n", md->dev_number); + + printf("cnt_corrected_read: %" PRIu32 "\n", md->cnt_corrected_read); + + printf("device_uuid: "); + bytefield_print(md->device_uuid, 16); + printf("\n"); + + printf("devflags: 0x%" PRIx8 "\n", md->devflags); + + printf("events: %" PRIu64 "\n", md->events); + + if (md->resync_offset == ~(0ULL)) + printf("resync_offset: 0\n"); + else + printf("resync_offset: %" PRIu64 "\n", md->resync_offset); + + printf("sb_csum: 0x%" PRIx32 "\n", md->sb_csum); + + printf("max_dev: %" PRIu32 "\n", md->max_dev); + + printf("dev_roles: "); + for (uint32_t d = 0; d < md->max_dev; d++) { + printf("0x%" PRIx16, md->dev_roles[d]); + if (d + 1 < md->max_dev) + printf(", "); + } + printf("\n"); +} + +static void *meta_md_alloc_struct(void) +{ + /* 1KiB - 256 meta size + max 384 devices */ + return calloc(1, MD_SIZE * 512); +} + +#if 0 +static void meta_md_encode(void *md_v, void *block) +{ + HR_DEBUG("%s()", __func__); + + (void)md_v; + (void)block; +} +#endif + +static errno_t meta_md_decode(const void *block, void *md_v) +{ + HR_DEBUG("%s()", __func__); + + errno_t rc = EOK; + struct mdp_superblock_1 *md = md_v; + + struct mdp_superblock_1 *scratch_md = meta_md_alloc_struct(); + if (scratch_md == NULL) + return ENOMEM; + + memcpy(scratch_md, block, meta_md_get_size() * 512); + + md->magic = uint32_t_le2host(scratch_md->magic); + if (md->magic != MD_MAGIC) { + rc = EINVAL; + goto error; + } + + md->major_version = uint32_t_le2host(scratch_md->major_version); + if (md->major_version != 1) { + HR_DEBUG("unsupported metadata version\n"); + rc = EINVAL; + goto error; + } + + md->feature_map = uint32_t_le2host(scratch_md->feature_map); + if (md->feature_map != 0x0) { + HR_DEBUG("unsupported feature map bits\n"); + rc = EINVAL; + goto error; + } + + memcpy(md->set_uuid, scratch_md->set_uuid, 16); + + memcpy(md->set_name, scratch_md->set_name, 32); + + md->ctime = uint64_t_le2host(scratch_md->ctime); + + md->level = uint32_t_le2host(scratch_md->level); + switch (md->level) { + case 0: + case 1: + case 4: + case 5: + break; + default: + HR_DEBUG("unsupported level\n"); + rc = EINVAL; + goto error; + } + + md->layout = uint32_t_le2host(scratch_md->layout); + if (md->level == 5) { + switch (md->layout) { + case ALGORITHM_LEFT_ASYMMETRIC: + case ALGORITHM_RIGHT_ASYMMETRIC: + case ALGORITHM_LEFT_SYMMETRIC: + break; + default: + HR_DEBUG("unsupported layout\n"); + rc = EINVAL; + goto error; + } + } else if (md->level == 4) { + if (md->layout != 0) { + HR_DEBUG("unsupported layout\n"); + rc = EINVAL; + goto error; + } + } + + md->size = uint64_t_le2host(scratch_md->size); + + md->chunksize = uint32_t_le2host(scratch_md->chunksize); + + md->raid_disks = uint32_t_le2host(scratch_md->raid_disks); + if (md->raid_disks > HR_MAX_EXTENTS) { + rc = EINVAL; + goto error; + } + + md->data_offset = uint64_t_le2host(scratch_md->data_offset); + + md->data_size = uint64_t_le2host(scratch_md->data_size); + if (md->data_size != md->size) { + rc = EINVAL; + goto error; + } + + md->super_offset = uint64_t_le2host(scratch_md->super_offset); + if (md->super_offset != MD_OFFSET) { + rc = EINVAL; + goto error; + } + + md->dev_number = uint32_t_le2host(scratch_md->dev_number); + + md->cnt_corrected_read = + uint32_t_le2host(scratch_md->cnt_corrected_read); + + memcpy(md->device_uuid, scratch_md->device_uuid, 16); + + md->devflags = scratch_md->devflags; + + md->bblog_shift = scratch_md->bblog_shift; + + md->bblog_size = uint16_t_le2host(scratch_md->bblog_size); + + md->bblog_offset = uint32_t_le2host(scratch_md->bblog_offset); + + md->utime = uint64_t_le2host(scratch_md->utime); + + md->events = uint64_t_le2host(scratch_md->events); + + md->resync_offset = uint64_t_le2host(scratch_md->resync_offset); + if (md->resync_offset != ~(0ULL)) { + rc = EINVAL; + goto error; + } + + md->sb_csum = uint32_t_le2host(scratch_md->sb_csum); + + md->max_dev = uint32_t_le2host(scratch_md->max_dev); + if (md->max_dev > 256 + 128) { + rc = EINVAL; + goto error; + } + + for (uint32_t d = 0; d < md->max_dev; d++) + md->dev_roles[d] = uint16_t_le2host(scratch_md->dev_roles[d]); + +error: + free(scratch_md); + + return rc; +} + +static errno_t meta_md_get_block(service_id_t dev, void **rblock) +{ + HR_DEBUG("%s()", __func__); + + errno_t rc; + uint64_t blkno; + size_t bsize; + void *block; + + if (rblock == NULL) + return EINVAL; + + rc = block_get_bsize(dev, &bsize); + if (rc != EOK) + return rc; + + if (bsize != 512) + return EINVAL; + + rc = block_get_nblocks(dev, &blkno); + if (rc != EOK) + return rc; + + if (blkno < MD_OFFSET + MD_SIZE) + return EINVAL; + + block = malloc(bsize * MD_SIZE); + if (block == NULL) + return ENOMEM; + + rc = hr_read_direct(dev, MD_OFFSET, MD_SIZE, block); + if (rc != EOK) { + free(block); + return rc; + } + + *rblock = block; + return EOK; +} + +#if 0 +static errno_t meta_md_write_block(service_id_t dev, const void *block) +{ + HR_DEBUG("%s()", __func__); + + errno_t rc; + uint64_t blkno; + size_t bsize; + + rc = block_get_bsize(dev, &bsize); + if (rc != EOK) + return rc; + + if (bsize != 512) + return EINVAL; + + rc = block_get_nblocks(dev, &blkno); + if (rc != EOK) + return rc; + + if (blkno < MD_OFFSET + MD_SIZE) + return EINVAL; + + rc = hr_write_direct(dev, MD_OFFSET, MD_SIZE, block); + + return rc; +} +#endif + +static bool meta_md_has_valid_magic(const void *md_v) +{ + HR_DEBUG("%s()", __func__); + + const struct mdp_superblock_1 *md = md_v; + + if (md->magic != MD_MAGIC) + return false; + + return true; +} + +/** @} + */ diff --git a/uspace/srv/bd/hr/metadata/foreign/md/md_p.h b/uspace/srv/bd/hr/metadata/foreign/md/md_p.h new file mode 100644 index 0000000000..64492d5165 --- /dev/null +++ b/uspace/srv/bd/hr/metadata/foreign/md/md_p.h @@ -0,0 +1,140 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +/* + * md_p.h : physical layout of Linux RAID devices + * Copyright (C) 1996-98 Ingo Molnar, Gadi Oxman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + */ + +/** @addtogroup hr + * @{ + */ +/** + * @file + */ + +#ifndef _HR_METADATA_FOREIGN_MD_H +#define _HR_METADATA_FOREIGN_MD_H + +typedef uint64_t __le64; +typedef uint32_t __le32; +typedef uint16_t __le16; +typedef uint8_t __u8; + +/* in 512 blocks */ +#define MD_OFFSET 8 +#define MD_SIZE 2 + +/* XXX: this is actually not used when assembling */ +#define MD_DATA_OFFSET 2048 + +#define MD_MAGIC 0xa92b4efc + +/* + * The version-1 superblock : + * All numeric fields are little-endian. + * + * total size: 256 bytes plus 2 per device. + * 1K allows 384 devices. + */ +struct mdp_superblock_1 { + /* constant array information - 128 bytes */ + __le32 magic; /* MD_SB_MAGIC: 0xa92b4efc - little endian */ + __le32 major_version; /* 1 */ + __le32 feature_map; /* bit 0 set if 'bitmap_offset' is meaningful */ + __le32 pad0; /* always set to 0 when writing */ + + __u8 set_uuid[16]; /* user-space generated. */ + char set_name[32]; /* set and interpreted by user-space */ + + __le64 ctime; /* lo 40 bits are seconds, top 24 are microseconds or 0 */ + __le32 level; /* 0,1,4,5, -1 (linear) */ + __le32 layout; /* only for raid5 and raid10 currently */ + __le64 size; /* used size of component devices, in 512byte sectors */ + + __le32 chunksize; /* in 512byte sectors */ + __le32 raid_disks; + union { + __le32 bitmap_offset; + /* + * sectors after start of superblock that bitmap starts + * NOTE: signed, so bitmap can be before superblock + * only meaningful of feature_map[0] is set. + */ + + /* only meaningful when feature_map[MD_FEATURE_PPL] is set */ + struct { + __le16 offset; /* sectors from start of superblock that ppl starts (signed) */ + __le16 size; /* ppl size in sectors */ + } ppl; + }; + + /* These are only valid with feature bit '4' */ + __le32 new_level; /* new level we are reshaping to */ + __le64 reshape_position; /* next address in array-space for reshape */ + __le32 delta_disks; /* change in number of raid_disks */ + __le32 new_layout; /* new layout */ + __le32 new_chunk; /* new chunk size (512byte sectors) */ + __le32 new_offset; + /* + * signed number to add to data_offset in new + * layout. 0 == no-change. This can be + * different on each device in the array. + */ + + /* constant this-device information - 64 bytes */ + __le64 data_offset; /* sector start of data, often 0 */ + __le64 data_size; /* sectors in this device that can be used for data */ + __le64 super_offset; /* sector start of this superblock */ + union { + __le64 recovery_offset;/* sectors before this offset (from data_offset) have been recovered */ + __le64 journal_tail;/* journal tail of journal device (from data_offset) */ + }; + __le32 dev_number; /* permanent identifier of this device - not role in raid */ + __le32 cnt_corrected_read; /* number of read errors that were corrected by re-writing */ + __u8 device_uuid[16]; /* user-space setable, ignored by kernel */ + __u8 devflags; /* per-device flags. Only two defined... */ +#define WriteMostly1 1 /* mask for writemostly flag in above */ +#define FailFast1 2 /* Should avoid retries and fixups and just fail */ + /* + * Bad block log. If there are any bad blocks the feature flag is set. + * If offset and size are non-zero, that space is reserved and available + */ + __u8 bblog_shift; /* shift from sectors to block size */ + __le16 bblog_size; /* number of sectors reserved for list */ + __le32 bblog_offset; + /* + * sector offset from superblock to bblog, + * signed - not unsigned + */ + + /* array state information - 64 bytes */ + __le64 utime; /* 40 bits second, 24 bits microseconds */ + __le64 events; /* incremented when superblock updated */ + __le64 resync_offset; /* data before this offset (from data_offset) known to be in sync */ + __le32 sb_csum; /* checksum up to devs[max_dev] */ + __le32 max_dev; /* size of devs[] array to consider */ + __u8 pad3[64 - 32]; /* set to 0 when writing */ + + /* + * device state information. Indexed by dev_number. + * 2 bytes per device + * Note there are no per-device state flags. State information is rolled + * into the 'roles' value. If a device is spare or faulty, then it doesn't + * have a meaningful role. + */ + __le16 dev_roles[]; /* role in array, or 0xffff for a spare, or 0xfffe for faulty */ +}; + +/* from mdadm.h */ +#define ALGORITHM_LEFT_ASYMMETRIC 0 +#define ALGORITHM_RIGHT_ASYMMETRIC 1 +#define ALGORITHM_LEFT_SYMMETRIC 2 + +#endif + +/** @} + */ diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index 548f340859..2f984ae79d 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -59,12 +59,14 @@ extern hr_superblock_ops_t metadata_native_ops; extern hr_superblock_ops_t metadata_gmirror_ops; extern hr_superblock_ops_t metadata_gstripe_ops; extern hr_superblock_ops_t metadata_softraid_ops; +extern hr_superblock_ops_t metadata_md_ops; static hr_superblock_ops_t *hr_superblock_ops_all[] = { [HR_METADATA_NATIVE] = &metadata_native_ops, [HR_METADATA_GEOM_MIRROR] = &metadata_gmirror_ops, [HR_METADATA_GEOM_STRIPE] = &metadata_gstripe_ops, - [HR_METADATA_SOFTRAID] = &metadata_softraid_ops + [HR_METADATA_SOFTRAID] = &metadata_softraid_ops, + [HR_METADATA_MD] = &metadata_md_ops }; hr_superblock_ops_t *hr_get_meta_type_ops(hr_metadata_type_t type) From 0dbd4a9ebab089fd782ed2811cceff7bc6545145 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 29 Jun 2025 00:52:18 +0200 Subject: [PATCH 289/324] hr: metadata: validate magic early in decode --- .../bd/hr/metadata/foreign/geom/g_mirror.h | 3 +++ .../bd/hr/metadata/foreign/geom/hr_g_mirror.c | 20 +------------- .../bd/hr/metadata/foreign/geom/hr_g_stripe.c | 27 +++++-------------- uspace/srv/bd/hr/metadata/foreign/md/hr_md.c | 20 +------------- .../metadata/foreign/softraid/hr_softraid.c | 20 +------------- uspace/srv/bd/hr/metadata/native.c | 10 +++---- uspace/srv/bd/hr/superblock.c | 7 +++-- 7 files changed, 20 insertions(+), 87 deletions(-) diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/g_mirror.h b/uspace/srv/bd/hr/metadata/foreign/geom/g_mirror.h index d6a4397300..a49fde9ad1 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/g_mirror.h +++ b/uspace/srv/bd/hr/metadata/foreign/geom/g_mirror.h @@ -171,6 +171,9 @@ mirror_metadata_decode(const u_char *data, struct g_mirror_metadata *md) int error; bcopy(data, md->md_magic, 16); + if (str_lcmp(md->md_magic, G_MIRROR_MAGIC, 16) != 0) + return (EINVAL); + md->md_version = le32dec(data + 16); switch (md->md_version) { case 4: diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c index b978ce6f28..08bf2ec54f 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c @@ -59,7 +59,6 @@ static void *meta_gmirror_alloc_struct(void); static errno_t meta_gmirror_decode(const void *, void *); static errno_t meta_gmirror_get_block(service_id_t, void **); /* static errno_t meta_gmirror_write_block(service_id_t, const void *); */ -static bool meta_gmirror_has_valid_magic(const void *); static errno_t meta_gmirror_probe(service_id_t, void **); static errno_t meta_gmirror_init_vol2meta(hr_volume_t *); @@ -115,17 +114,12 @@ static errno_t meta_gmirror_probe(service_id_t svc_id, void **rmd) if (rc != EOK) goto error; - if (!meta_gmirror_has_valid_magic(metadata_struct)) { - rc = ENOFS; - goto error; - } - *rmd = metadata_struct; return EOK; error: free(metadata_struct); - return ENOFS; + return rc; } static errno_t meta_gmirror_init_vol2meta(hr_volume_t *vol) @@ -400,17 +394,5 @@ static errno_t meta_gmirror_write_block(service_id_t dev, const void *block) } #endif -static bool meta_gmirror_has_valid_magic(const void *md_v) -{ - HR_DEBUG("%s()", __func__); - - const struct g_mirror_metadata *md = md_v; - - if (str_lcmp(md->md_magic, G_MIRROR_MAGIC, 16) != 0) - return false; - - return true; -} - /** @} */ diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c index 7c7e099af1..1f0db8edc4 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c @@ -59,7 +59,6 @@ static void *meta_gstripe_alloc_struct(void); static errno_t meta_gstripe_decode(const void *, void *); static errno_t meta_gstripe_get_block(service_id_t, void **); /* static errno_t meta_gstripe_write_block(service_id_t, const void *); */ -static bool meta_gstripe_has_valid_magic(const void *); static errno_t meta_gstripe_probe(service_id_t, void **); static errno_t meta_gstripe_init_vol2meta(hr_volume_t *); @@ -115,17 +114,12 @@ static errno_t meta_gstripe_probe(service_id_t svc_id, void **rmd) if (rc != EOK) goto error; - if (!meta_gstripe_has_valid_magic(metadata_struct)) { - rc = ENOFS; - goto error; - } - *rmd = metadata_struct; return EOK; error: free(metadata_struct); - return ENOFS; + return rc; } static errno_t meta_gstripe_init_vol2meta(hr_volume_t *vol) @@ -317,7 +311,12 @@ static errno_t meta_gstripe_decode(const void *block, void *md_v) { HR_DEBUG("%s()", __func__); - stripe_metadata_decode(block, md_v); + struct g_stripe_metadata *md = md_v; + + stripe_metadata_decode(block, md); + + if (str_lcmp(md->md_magic, G_STRIPE_MAGIC, 16) != 0) + return EINVAL; return EOK; } @@ -396,17 +395,5 @@ static errno_t meta_gstripe_write_block(service_id_t dev, const void *block) } #endif -static bool meta_gstripe_has_valid_magic(const void *md_v) -{ - HR_DEBUG("%s()", __func__); - - const struct g_stripe_metadata *md = md_v; - - if (str_lcmp(md->md_magic, G_STRIPE_MAGIC, 16) != 0) - return false; - - return true; -} - /** @} */ diff --git a/uspace/srv/bd/hr/metadata/foreign/md/hr_md.c b/uspace/srv/bd/hr/metadata/foreign/md/hr_md.c index 49c94c8244..e9cc551da8 100644 --- a/uspace/srv/bd/hr/metadata/foreign/md/hr_md.c +++ b/uspace/srv/bd/hr/metadata/foreign/md/hr_md.c @@ -58,7 +58,6 @@ static void *meta_md_alloc_struct(void); static errno_t meta_md_decode(const void *, void *); static errno_t meta_md_get_block(service_id_t, void **); /* static errno_t meta_md_write_block(service_id_t, const void *); */ -static bool meta_md_has_valid_magic(const void *); static errno_t meta_md_probe(service_id_t, void **); static errno_t meta_md_init_vol2meta(hr_volume_t *); @@ -114,17 +113,12 @@ static errno_t meta_md_probe(service_id_t svc_id, void **rmd) if (rc != EOK) goto error; - if (!meta_md_has_valid_magic(metadata_struct)) { - rc = ENOFS; - goto error; - } - *rmd = metadata_struct; return EOK; error: free(metadata_struct); - return ENOFS; + return rc; } static errno_t meta_md_init_vol2meta(hr_volume_t *vol) @@ -609,17 +603,5 @@ static errno_t meta_md_write_block(service_id_t dev, const void *block) } #endif -static bool meta_md_has_valid_magic(const void *md_v) -{ - HR_DEBUG("%s()", __func__); - - const struct mdp_superblock_1 *md = md_v; - - if (md->magic != MD_MAGIC) - return false; - - return true; -} - /** @} */ diff --git a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c index ec913f5e7a..d54efaccf7 100644 --- a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c +++ b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c @@ -59,7 +59,6 @@ static void *meta_softraid_alloc_struct(void); static errno_t meta_softraid_decode(const void *, void *); static errno_t meta_softraid_get_block(service_id_t, void **); /* static errno_t meta_softraid_write_block(service_id_t, const void *); */ -static bool meta_softraid_has_valid_magic(const void *); static errno_t meta_softraid_probe(service_id_t, void **); static errno_t meta_softraid_init_vol2meta(hr_volume_t *); @@ -115,17 +114,12 @@ static errno_t meta_softraid_probe(service_id_t svc_id, void **rmd) if (rc != EOK) goto error; - if (!meta_softraid_has_valid_magic(metadata_struct)) { - rc = ENOFS; - goto error; - } - *rmd = metadata_struct; return EOK; error: free(metadata_struct); - return ENOFS; + return rc; } static errno_t meta_softraid_init_vol2meta(hr_volume_t *vol) @@ -538,17 +532,5 @@ static errno_t meta_softraid_write_block(service_id_t dev, const void *block) } #endif -static bool meta_softraid_has_valid_magic(const void *md_v) -{ - HR_DEBUG("%s()", __func__); - - const struct sr_metadata *md = md_v; - - if (md->ssdi.ssd_magic != SR_MAGIC) - return false; - - return true; -} - /** @} */ diff --git a/uspace/srv/bd/hr/metadata/native.c b/uspace/srv/bd/hr/metadata/native.c index 15ff9fb759..21d99447de 100644 --- a/uspace/srv/bd/hr/metadata/native.c +++ b/uspace/srv/bd/hr/metadata/native.c @@ -115,17 +115,12 @@ static errno_t meta_native_probe(service_id_t svc_id, void **rmd) if (rc != EOK) goto error; - if (!meta_native_has_valid_magic(metadata_struct)) { - rc = ENOFS; - goto error; - } - *rmd = metadata_struct; return EOK; error: free(metadata_struct); - return ENOFS; + return rc; } static errno_t meta_native_init_vol2meta(hr_volume_t *vol) @@ -439,6 +434,9 @@ static errno_t meta_native_decode(const void *block, void *md_v) memcpy(&scratch_md, block, sizeof(hr_metadata_t)); memcpy(metadata->magic, scratch_md.magic, HR_NATIVE_MAGIC_SIZE); + if (!meta_native_has_valid_magic(metadata)) + return EINVAL; + memcpy(metadata->uuid, scratch_md.uuid, HR_NATIVE_UUID_LEN); metadata->data_blkno = uint64_t_le2host(scratch_md.data_blkno); diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index 2f984ae79d..7c0047686f 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -95,11 +95,10 @@ errno_t hr_find_metadata(service_id_t svc_id, void **rmetadata, meta_ops = hr_superblock_ops_all[type]; rc = meta_ops->probe(svc_id, &metadata_struct); - if (rc != EOK) { - if (rc != ENOFS) - return rc; + if (rc == ENOMEM) + return ENOMEM; + if (rc != EOK) continue; - } *rmetadata = metadata_struct; *rtype = type; From 9c9955abd28cb780d1099f45dcb9113b5e8f6833 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 29 Jun 2025 01:42:54 +0200 Subject: [PATCH 290/324] hr: metadata/softraid: invalidate rebuild chunk --- .../srv/bd/hr/metadata/foreign/softraid/hr_softraid.c | 7 ++++++- .../srv/bd/hr/metadata/foreign/softraid/softraidvar.h | 10 ++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c index d54efaccf7..2d350422f7 100644 --- a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c +++ b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c @@ -189,8 +189,13 @@ static errno_t meta_softraid_init_meta2vol(const list_t *list, hr_volume_t *vol) vol->extents[index].svc_id = iter->svc_id; iter->fini = false; + struct sr_meta_chunk *mc = + (struct sr_meta_chunk *)(main_meta + 1); + mc += index; + /* for now no ssd_rebuild handling for saved REBUILD */ - if (iter_meta->ssd_ondisk == max_counter_val) + if (iter_meta->ssd_ondisk == max_counter_val && + mc->scm_status != BIOC_SDREBUILD) vol->extents[index].state = HR_EXT_ONLINE; else vol->extents[index].state = HR_EXT_INVALID; diff --git a/uspace/srv/bd/hr/metadata/foreign/softraid/softraidvar.h b/uspace/srv/bd/hr/metadata/foreign/softraid/softraidvar.h index 0c05014a43..927fd60165 100644 --- a/uspace/srv/bd/hr/metadata/foreign/softraid/softraidvar.h +++ b/uspace/srv/bd/hr/metadata/foreign/softraid/softraidvar.h @@ -39,6 +39,16 @@ typedef uint64_t u_int64_t; #define _DEV_BSHIFT 9 /* log2(DEV_BSIZE) */ #define DEV_BSIZE (1 << _DEV_BSHIFT) +/* copied from :struct bioc_disk */ +#define BIOC_SDONLINE 0x00 +#define BIOC_SDOFFLINE 0x01 +#define BIOC_SDFAILED 0x02 +#define BIOC_SDREBUILD 0x03 +#define BIOC_SDHOTSPARE 0x04 +#define BIOC_SDUNUSED 0x05 +#define BIOC_SDSCRUB 0x06 +#define BIOC_SDINVALID 0xff + /* here continues stripped down and slightly modified softraidvat.h */ #define MD5_DIGEST_LENGTH 16 From e5c35800c07616e5b6a5c3360898642336ddea94 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 29 Jun 2025 11:20:23 +0200 Subject: [PATCH 291/324] hr: add HR_METADATA_ALLOW_REBUILD flag For now we want to be conservative with what we allow foreign metadata volumes to do. --- uspace/srv/bd/hr/metadata/native.c | 1 + uspace/srv/bd/hr/raid1.c | 3 +++ uspace/srv/bd/hr/raid5.c | 3 +++ uspace/srv/bd/hr/superblock.h | 1 + 4 files changed, 8 insertions(+) diff --git a/uspace/srv/bd/hr/metadata/native.c b/uspace/srv/bd/hr/metadata/native.c index 21d99447de..34d597630f 100644 --- a/uspace/srv/bd/hr/metadata/native.c +++ b/uspace/srv/bd/hr/metadata/native.c @@ -347,6 +347,7 @@ static uint8_t meta_native_get_flags(void) uint8_t flags = 0; flags |= HR_METADATA_HOTSPARE_SUPPORT; + flags |= HR_METADATA_ALLOW_REBUILD; return flags; } diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 147058e344..9d832b05a0 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -454,6 +454,9 @@ static errno_t hr_raid1_rebuild(void *arg) hr_extent_t *rebuild_ext = NULL; errno_t rc; + if (!(vol->meta_ops->get_flags() & HR_METADATA_ALLOW_REBUILD)) + return ENOTSUP; + rc = hr_init_rebuild(vol, &rebuild_idx); if (rc != EOK) return rc; diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index d197e593ff..406851b7fd 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -716,6 +716,9 @@ static errno_t hr_raid5_rebuild(void *arg) size_t rebuild_idx; void *buf = NULL, *xorbuf = NULL; + if (!(vol->meta_ops->get_flags() & HR_METADATA_ALLOW_REBUILD)) + return ENOTSUP; + rc = hr_init_rebuild(vol, &rebuild_idx); if (rc != EOK) return rc; diff --git a/uspace/srv/bd/hr/superblock.h b/uspace/srv/bd/hr/superblock.h index 5d2addd20e..075e44f109 100644 --- a/uspace/srv/bd/hr/superblock.h +++ b/uspace/srv/bd/hr/superblock.h @@ -41,6 +41,7 @@ typedef struct hr_volume hr_volume_t; #define HR_METADATA_HOTSPARE_SUPPORT 0x01 +#define HR_METADATA_ALLOW_REBUILD 0x02 typedef struct hr_superblock_ops { errno_t (*probe)(service_id_t, void **); From 93ea452072c4080f314fba3f817b325ecc20452a Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 29 Jun 2025 11:38:41 +0200 Subject: [PATCH 292/324] hr: util.c: catch meta2vol() error --- uspace/srv/bd/hr/util.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 47f29a9812..69c7ff4435 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -851,6 +851,8 @@ static errno_t hr_util_assemble_from_matching_list(list_t *list, return rc; meta_ops->init_meta2vol(list, vol); + if (rc != EOK) + goto error; rc = vol->hr_ops.create(vol); if (rc != EOK) From 150adbd2e618fb049e1613658a0e20af0a3ed593 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 29 Jun 2025 12:08:40 +0200 Subject: [PATCH 293/324] hr: add NOOP metadata type --- uspace/app/hrctl/hrctl.c | 27 +++-- uspace/lib/device/include/hr.h | 8 +- uspace/lib/device/src/hr.c | 2 + uspace/srv/bd/hr/hr.c | 10 +- uspace/srv/bd/hr/meson.build | 1 + uspace/srv/bd/hr/metadata/noop.c | 177 +++++++++++++++++++++++++++++++ uspace/srv/bd/hr/superblock.c | 9 +- 7 files changed, 221 insertions(+), 13 deletions(-) create mode 100644 uspace/srv/bd/hr/metadata/noop.c diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index 498b7ad8ad..d8533f8fb7 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -51,8 +51,8 @@ static void usage(void); static errno_t fill_config_devs(int, char **, hr_config_t *); static errno_t get_vol_configs_from_sif(const char *, hr_config_t **, size_t *); -static int create_from_config(hr_t *, const char *); -static int create_from_argv(hr_t *, int, char **); +static int create_from_config(hr_t *, const char *, uint8_t); +static int create_from_argv(hr_t *, int, char **, uint8_t); static int handle_create(hr_t *, int, char **); static int assemble_from_config(hr_t *, const char *); static int assemble_from_argv(hr_t *, int, char **); @@ -69,7 +69,7 @@ static const char usage_str[] = "Options:\n" " -h, --help Display this message and exit.\n" "\n" - " -c, --create Create a volume, options:\n" + " -c, --create [--no_meta] Create a volume, options:\n" " name {-l , --level level} device... manual device specification, or\n" " -f configuration.sif create from configuration file.\n" "\n" @@ -107,6 +107,7 @@ static const char usage_str[] = "\t\thrctl -s\n" "\n" "Notes:\n" + " Add --no_meta after --create to disable storing on-disk metadata.\n" " Simulating an extent failure with -m volume -f index is dangerous. It marks\n" " metadata as dirty in other healthy extents, and zeroes out the superblock\n" " on the specified extent.\n" @@ -340,7 +341,8 @@ static errno_t get_vol_configs_from_sif(const char *path, hr_config_t **rcfgs, return rc; } -static int create_from_config(hr_t *hr, const char *config_path) +static int create_from_config(hr_t *hr, const char *config_path, + uint8_t vol_flags) { hr_config_t *vol_configs = NULL; size_t vol_count = 0; @@ -351,6 +353,9 @@ static int create_from_config(hr_t *hr, const char *config_path) return EXIT_FAILURE; } + for (size_t i = 0; i < vol_count; i++) + vol_configs[i].vol_flags |= vol_flags; + for (size_t i = 0; i < vol_count; i++) { rc = hr_create(hr, &vol_configs[i]); if (rc != EOK) { @@ -367,7 +372,7 @@ static int create_from_config(hr_t *hr, const char *config_path) return EXIT_SUCCESS; } -static int create_from_argv(hr_t *hr, int argc, char **argv) +static int create_from_argv(hr_t *hr, int argc, char **argv, uint8_t vol_flags) { /* we need name + --level + arg + at least one extent */ if (optind + 3 >= argc) { @@ -381,6 +386,8 @@ static int create_from_argv(hr_t *hr, int argc, char **argv) return EXIT_FAILURE; } + vol_config->vol_flags |= vol_flags; + const char *name = argv[optind++]; if (str_size(name) >= HR_DEVNAME_LEN) { printf(NAME ": devname must be less then 32 bytes.\n"); @@ -440,12 +447,18 @@ static int create_from_argv(hr_t *hr, int argc, char **argv) static int handle_create(hr_t *hr, int argc, char **argv) { int rc; + uint8_t vol_flags = 0; if (optind >= argc) { printf(NAME ": no arguments to --create\n"); return EXIT_FAILURE; } + if (str_cmp(argv[optind], "--no_meta") == 0) { + vol_flags |= HR_VOL_FLAG_NOOP_META; + optind++; + } + if (str_cmp(argv[optind], "-f") == 0) { optind++; if (optind >= argc) { @@ -460,9 +473,9 @@ static int handle_create(hr_t *hr, int argc, char **argv) return EXIT_FAILURE; } - rc = create_from_config(hr, config_path); + rc = create_from_config(hr, config_path, vol_flags); } else { - rc = create_from_argv(hr, argc, argv); + rc = create_from_argv(hr, argc, argv, vol_flags); } return rc; diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index f5c06c1b5d..8210a7bb40 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -87,9 +87,14 @@ typedef enum { HR_METADATA_GEOM_STRIPE, HR_METADATA_SOFTRAID, HR_METADATA_MD, - HR_METADATA_LAST_DUMMY + HR_METADATA_NOOP, + HR_METADATA_LAST_PLACEHOLDER } hr_metadata_type_t; +typedef enum hr_vol_flag { + HR_VOL_FLAG_NOOP_META = 0x01 +} hr_vol_flag_t; + typedef struct hr { async_sess_t *sess; } hr_t; @@ -99,6 +104,7 @@ typedef struct hr_config { service_id_t devs[HR_MAX_EXTENTS]; size_t dev_no; hr_level_t level; + uint8_t vol_flags; } hr_config_t; typedef struct hr_extent { diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index 489818292f..619504749d 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -553,6 +553,8 @@ const char *hr_get_metadata_type_str(hr_metadata_type_t type) return "OpenBSD softraid"; case HR_METADATA_MD: return "Linux Multiple Device"; + case HR_METADATA_NOOP: + return "NOOP Metadata"; default: return "Invalid metadata type value"; } diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 8323bac8ad..6648212705 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -130,8 +130,14 @@ static void hr_create_srv(ipc_call_t *icall) } } - rc = hr_create_vol_struct(&vol, cfg->level, cfg->devname, - HR_METADATA_NATIVE); + hr_metadata_type_t meta_type; + if (cfg->vol_flags & HR_VOL_FLAG_NOOP_META) + meta_type = HR_METADATA_NOOP; + else + meta_type = HR_METADATA_NATIVE; + + printf("creating with type %d\n", meta_type); + rc = hr_create_vol_struct(&vol, cfg->level, cfg->devname, meta_type); if (rc != EOK) { free(cfg); async_answer_0(icall, rc); diff --git a/uspace/srv/bd/hr/meson.build b/uspace/srv/bd/hr/meson.build index d30437e0db..de7f015ef7 100644 --- a/uspace/srv/bd/hr/meson.build +++ b/uspace/srv/bd/hr/meson.build @@ -37,6 +37,7 @@ src = files( 'metadata/foreign/softraid/hr_softraid.c', 'metadata/foreign/softraid/softraid.c', 'metadata/native.c', + 'metadata/noop.c', 'parity_stripe.c', 'raid0.c', 'raid1.c', diff --git a/uspace/srv/bd/hr/metadata/noop.c b/uspace/srv/bd/hr/metadata/noop.c new file mode 100644 index 0000000000..d0d76d83a5 --- /dev/null +++ b/uspace/srv/bd/hr/metadata/noop.c @@ -0,0 +1,177 @@ +/* + * 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 "../superblock.h" +#include "../util.h" +#include "../var.h" + +static errno_t meta_noop_probe(service_id_t, void **); +static errno_t meta_noop_init_vol2meta(hr_volume_t *); +static errno_t meta_noop_init_meta2vol(const list_t *, hr_volume_t *); +static errno_t meta_noop_erase_block(service_id_t); +static bool meta_noop_compare_uuids(const void *, const void *); +static void meta_noop_inc_counter(hr_volume_t *); +static errno_t meta_noop_save(hr_volume_t *, bool); +static errno_t meta_noop_save_ext(hr_volume_t *, size_t, bool); +static const char *meta_noop_get_devname(const void *); +static hr_level_t meta_noop_get_level(const void *); +static uint64_t meta_noop_get_data_offset(void); +static size_t meta_noop_get_size(void); +static uint8_t meta_noop_get_flags(void); +static hr_metadata_type_t meta_noop_get_type(void); +static void meta_noop_dump(const void *); + +hr_superblock_ops_t noop_ops = { + .probe = meta_noop_probe, + .init_vol2meta = meta_noop_init_vol2meta, + .init_meta2vol = meta_noop_init_meta2vol, + .erase_block = meta_noop_erase_block, + .compare_uuids = meta_noop_compare_uuids, + .inc_counter = meta_noop_inc_counter, + .save = meta_noop_save, + .save_ext = meta_noop_save_ext, + .get_devname = meta_noop_get_devname, + .get_level = meta_noop_get_level, + .get_data_offset = meta_noop_get_data_offset, + .get_size = meta_noop_get_size, + .get_flags = meta_noop_get_flags, + .get_type = meta_noop_get_type, + .dump = meta_noop_dump +}; + +static errno_t meta_noop_probe(service_id_t svc_id, void **rmd) +{ + HR_DEBUG("%s()", __func__); + + return ENOTSUP; +} + +static errno_t meta_noop_init_vol2meta(hr_volume_t *vol) +{ + HR_DEBUG("%s()", __func__); + + return EOK; +} + +static errno_t meta_noop_init_meta2vol(const list_t *list, hr_volume_t *vol) +{ + HR_DEBUG("%s()", __func__); + + return ENOTSUP; +} + +static errno_t meta_noop_erase_block(service_id_t dev) +{ + HR_DEBUG("%s()", __func__); + + return EOK; +} + +static bool meta_noop_compare_uuids(const void *m1p, const void *m2p) +{ + return false; +} + +static void meta_noop_inc_counter(hr_volume_t *vol) +{ + (void)vol; +} + +static errno_t meta_noop_save(hr_volume_t *vol, bool with_state_callback) +{ + HR_DEBUG("%s()", __func__); + + return EOK; +} + +static errno_t meta_noop_save_ext(hr_volume_t *vol, size_t ext_idx, + bool with_state_callback) +{ + HR_DEBUG("%s()", __func__); + + return EOK; +} + +static const char *meta_noop_get_devname(const void *md_v) +{ + return NULL; +} + +static hr_level_t meta_noop_get_level(const void *md_v) +{ + return HR_LVL_UNKNOWN; +} + +static uint64_t meta_noop_get_data_offset(void) +{ + return 0; +} + +static size_t meta_noop_get_size(void) +{ + return 0; +} + +static uint8_t meta_noop_get_flags(void) +{ + HR_DEBUG("%s()", __func__); + + uint8_t flags = 0; + + flags |= HR_METADATA_HOTSPARE_SUPPORT; + flags |= HR_METADATA_ALLOW_REBUILD; + + return flags; +} + +static hr_metadata_type_t meta_noop_get_type(void) +{ + HR_DEBUG("%s()", __func__); + + return HR_METADATA_NOOP; +} + +static void meta_noop_dump(const void *md_v) +{ + HR_DEBUG("%s()", __func__); + + printf("NOOP Metadata\n"); +} + +/** @} + */ diff --git a/uspace/srv/bd/hr/superblock.c b/uspace/srv/bd/hr/superblock.c index 7c0047686f..c0893bb833 100644 --- a/uspace/srv/bd/hr/superblock.c +++ b/uspace/srv/bd/hr/superblock.c @@ -60,18 +60,21 @@ extern hr_superblock_ops_t metadata_gmirror_ops; extern hr_superblock_ops_t metadata_gstripe_ops; extern hr_superblock_ops_t metadata_softraid_ops; extern hr_superblock_ops_t metadata_md_ops; +extern hr_superblock_ops_t noop_ops; static hr_superblock_ops_t *hr_superblock_ops_all[] = { [HR_METADATA_NATIVE] = &metadata_native_ops, [HR_METADATA_GEOM_MIRROR] = &metadata_gmirror_ops, [HR_METADATA_GEOM_STRIPE] = &metadata_gstripe_ops, [HR_METADATA_SOFTRAID] = &metadata_softraid_ops, - [HR_METADATA_MD] = &metadata_md_ops + [HR_METADATA_MD] = &metadata_md_ops, + [HR_METADATA_NOOP] = &noop_ops }; hr_superblock_ops_t *hr_get_meta_type_ops(hr_metadata_type_t type) { - assert(type >= HR_METADATA_NATIVE && type < HR_METADATA_LAST_DUMMY); + assert(type >= HR_METADATA_NATIVE && + type < HR_METADATA_LAST_PLACEHOLDER); return hr_superblock_ops_all[type]; } @@ -91,7 +94,7 @@ errno_t hr_find_metadata(service_id_t svc_id, void **rmetadata, return EINVAL; volatile hr_metadata_type_t type = HR_METADATA_NATIVE; - for (; type < HR_METADATA_LAST_DUMMY; type++) { + for (; type < HR_METADATA_LAST_PLACEHOLDER; type++) { meta_ops = hr_superblock_ops_all[type]; rc = meta_ops->probe(svc_id, &metadata_struct); From 40ab4901cb1e9b228cc6eefc06ee1fa7e0415985 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 29 Jun 2025 12:29:31 +0200 Subject: [PATCH 294/324] hr: metadata/softraid: do not support dirty flag set --- uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c index 2d350422f7..8556d12cd7 100644 --- a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c +++ b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c @@ -395,6 +395,11 @@ static errno_t meta_softraid_decode(const void *block, void *md_v) memcpy(md->ssd_devname, scratch_md->ssd_devname, 32); md->ssd_meta_flags = uint32_t_le2host(scratch_md->ssd_meta_flags); + if (md->ssd_meta_flags & SR_META_DIRTY) { + HR_DEBUG("dirty metadata not supported\n"); + rc = EINVAL; + goto error; + } md->ssd_data_blkno = uint32_t_le2host(scratch_md->ssd_data_blkno); md->ssd_ondisk = uint64_t_le2host(scratch_md->ssd_ondisk); md->ssd_rebuild = int64_t_le2host(scratch_md->ssd_rebuild); From c095ad930651dd678944809ee7b162bf5a92c83a Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 29 Jun 2025 18:24:13 +0200 Subject: [PATCH 295/324] hr: metadata/native: remove old debug print --- uspace/srv/bd/hr/metadata/native.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/uspace/srv/bd/hr/metadata/native.c b/uspace/srv/bd/hr/metadata/native.c index 34d597630f..fb764fb2dc 100644 --- a/uspace/srv/bd/hr/metadata/native.c +++ b/uspace/srv/bd/hr/metadata/native.c @@ -204,8 +204,6 @@ static errno_t meta_native_init_meta2vol(const list_t *list, hr_volume_t *vol) if (iter_meta->rebuild_pos > 0) { final_ext_state = HR_EXT_REBUILD; vol->rebuild_blk = iter_meta->rebuild_pos; - printf("REBUILD SHOULD RESUME at %lu\n", - vol->rebuild_blk); } else { final_ext_state = HR_EXT_ONLINE; } From 4a775402f8e629e58202a566e0e3366bec40fb18 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 29 Jun 2025 18:27:07 +0200 Subject: [PATCH 296/324] hr: GEOM Mirror metadata saving support --- .../bd/hr/metadata/foreign/geom/hr_g_mirror.c | 103 ++++++++++++++---- 1 file changed, 81 insertions(+), 22 deletions(-) diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c index 08bf2ec54f..3b0881a3b7 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c @@ -55,10 +55,10 @@ /* not exposed */ static void *meta_gmirror_alloc_struct(void); -/* static void meta_gmirror_encode(void *, void *); */ +static void meta_gmirror_encode(void *, void *); static errno_t meta_gmirror_decode(const void *, void *); static errno_t meta_gmirror_get_block(service_id_t, void **); -/* static errno_t meta_gmirror_write_block(service_id_t, const void *); */ +static errno_t meta_gmirror_write_block(service_id_t, const void *); static errno_t meta_gmirror_probe(service_id_t, void **); static errno_t meta_gmirror_init_vol2meta(hr_volume_t *); @@ -171,21 +171,47 @@ static errno_t meta_gmirror_init_meta2vol(const list_t *list, hr_volume_t *vol) vol->bsize = main_meta->md_sectorsize; - vol->in_mem_md = calloc(1, sizeof(struct g_mirror_metadata)); + vol->in_mem_md = + calloc(vol->extent_no, sizeof(struct g_mirror_metadata)); if (vol->in_mem_md == NULL) return ENOMEM; memcpy(vol->in_mem_md, main_meta, sizeof(struct g_mirror_metadata)); + bool rebuild = false; + uint8_t index = 0; list_foreach(*list, link, struct dev_list_member, iter) { struct g_mirror_metadata *iter_meta = iter->md; + struct g_mirror_metadata *p = + ((struct g_mirror_metadata *)vol->in_mem_md) + index; + memcpy(p, iter_meta, sizeof(*p)); + vol->extents[index].svc_id = iter->svc_id; iter->fini = false; - /* for now no md_sync_offset handling for saved REBUILD */ - if (iter_meta->md_syncid == max_counter_val) + bool invalidate = false; + + if (iter_meta->md_dflags & G_MIRROR_DISK_FLAG_DIRTY) + invalidate = true; + if (iter_meta->md_syncid != max_counter_val) + invalidate = true; + + if (iter_meta->md_dflags & G_MIRROR_DISK_FLAG_SYNCHRONIZING && + !invalidate) { + if (rebuild) { + HR_DEBUG("only 1 rebuilt extent allowed"); + rc = EINVAL; + goto error; + } + rebuild = true; + vol->rebuild_blk = iter_meta->md_sync_offset; + } + + if (!rebuild && !invalidate) vol->extents[index].state = HR_EXT_ONLINE; + else if (rebuild && !invalidate) + vol->extents[index].state = HR_EXT_REBUILD; else vol->extents[index].state = HR_EXT_INVALID; @@ -224,9 +250,11 @@ static void meta_gmirror_inc_counter(hr_volume_t *vol) { fibril_mutex_lock(&vol->md_lock); - struct g_mirror_metadata *md = vol->in_mem_md; - - md->md_syncid++; + for (size_t d = 0; d < vol->extent_no; d++) { + struct g_mirror_metadata *md = + ((struct g_mirror_metadata *)vol->in_mem_md) + d; + md->md_syncid++; + } fibril_mutex_unlock(&vol->md_lock); } @@ -235,16 +263,14 @@ static errno_t meta_gmirror_save(hr_volume_t *vol, bool with_state_callback) { HR_DEBUG("%s()", __func__); - (void)vol; - (void)with_state_callback; + fibril_rwlock_read_lock(&vol->extents_lock); - /* - * cannot support right now, because would need to store the - * metadata for all disks, because of hardcoded provider names and - * more importantly, disk unique ids - */ + for (size_t i = 0; i < vol->extent_no; i++) + meta_gmirror_save_ext(vol, i, with_state_callback); - return ENOTSUP; + fibril_rwlock_read_unlock(&vol->extents_lock); + + return EOK; } static errno_t meta_gmirror_save_ext(hr_volume_t *vol, size_t ext_idx, @@ -252,7 +278,45 @@ static errno_t meta_gmirror_save_ext(hr_volume_t *vol, size_t ext_idx, { HR_DEBUG("%s()", __func__); - return ENOTSUP; + assert(fibril_rwlock_is_locked(&vol->extents_lock)); + + void *md_block = hr_calloc_waitok(1, vol->bsize); + + struct g_mirror_metadata *md = + ((struct g_mirror_metadata *)vol->in_mem_md) + ext_idx; + + hr_extent_t *ext = &vol->extents[ext_idx]; + + fibril_rwlock_read_lock(&vol->states_lock); + hr_ext_state_t s = ext->state; + fibril_rwlock_read_unlock(&vol->states_lock); + + if (s != HR_EXT_ONLINE && s != HR_EXT_REBUILD) { + return EINVAL; + } + + fibril_mutex_lock(&vol->md_lock); + + if (s == HR_EXT_REBUILD) { + md->md_sync_offset = vol->rebuild_blk; + md->md_dflags |= G_MIRROR_DISK_FLAG_SYNCHRONIZING; + } else { + md->md_sync_offset = 0; + md->md_dflags &= ~(G_MIRROR_DISK_FLAG_SYNCHRONIZING); + } + + meta_gmirror_encode(md, md_block); + errno_t rc = meta_gmirror_write_block(ext->svc_id, md_block); + if (rc != EOK && with_state_callback) + vol->hr_ops.ext_state_cb(vol, ext_idx, rc); + + fibril_mutex_unlock(&vol->md_lock); + + if (with_state_callback) + vol->hr_ops.vol_state_eval(vol); + + free(md_block); + return EOK; } static const char *meta_gmirror_get_devname(const void *md_v) @@ -302,15 +366,12 @@ static void *meta_gmirror_alloc_struct(void) { return calloc(1, sizeof(struct g_mirror_metadata)); } - -#if 0 static void meta_gmirror_encode(void *md_v, void *block) { HR_DEBUG("%s()", __func__); mirror_metadata_encode(md_v, block); } -#endif static errno_t meta_gmirror_decode(const void *block, void *md_v) { @@ -365,7 +426,6 @@ static errno_t meta_gmirror_get_block(service_id_t dev, void **rblock) return EOK; } -#if 0 static errno_t meta_gmirror_write_block(service_id_t dev, const void *block) { HR_DEBUG("%s()", __func__); @@ -392,7 +452,6 @@ static errno_t meta_gmirror_write_block(service_id_t dev, const void *block) return rc; } -#endif /** @} */ From b81ae12b1c672d8e1a113d2af63ea49eff413033 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 29 Jun 2025 18:27:35 +0200 Subject: [PATCH 297/324] hr: softraid metadata saving support --- .../metadata/foreign/softraid/hr_softraid.c | 183 +++++++++++++++--- 1 file changed, 161 insertions(+), 22 deletions(-) diff --git a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c index 8556d12cd7..44ab2298aa 100644 --- a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c +++ b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c @@ -55,10 +55,10 @@ /* not exposed */ static void *meta_softraid_alloc_struct(void); -/* static void meta_softraid_encode(void *, void *); */ +static void meta_softraid_encode(void *, void *); static errno_t meta_softraid_decode(const void *, void *); static errno_t meta_softraid_get_block(service_id_t, void **); -/* static errno_t meta_softraid_write_block(service_id_t, const void *); */ +static errno_t meta_softraid_write_block(service_id_t, const void *); static errno_t meta_softraid_probe(service_id_t, void **); static errno_t meta_softraid_init_vol2meta(hr_volume_t *); @@ -181,6 +181,7 @@ static errno_t meta_softraid_init_meta2vol(const list_t *list, hr_volume_t *vol) return ENOMEM; memcpy(vol->in_mem_md, main_meta, SR_META_SIZE * DEV_BSIZE); + bool rebuild = false; list_foreach(*list, link, struct dev_list_member, iter) { struct sr_metadata *iter_meta = iter->md; @@ -190,13 +191,29 @@ static errno_t meta_softraid_init_meta2vol(const list_t *list, hr_volume_t *vol) iter->fini = false; struct sr_meta_chunk *mc = - (struct sr_meta_chunk *)(main_meta + 1); - mc += index; + ((struct sr_meta_chunk *)(main_meta + 1)) + index; + + bool invalidate = false; + + if (iter_meta->ssd_meta_flags & SR_META_DIRTY) + invalidate = true; + if (iter_meta->ssd_ondisk != max_counter_val) + invalidate = true; + + if (mc->scm_status == BIOC_SDREBUILD && !invalidate) { + if (rebuild) { + HR_DEBUG("only 1 rebuilt extent allowed"); + rc = EINVAL; + goto error; + } + rebuild = true; + vol->rebuild_blk = iter_meta->ssd_rebuild; + } - /* for now no ssd_rebuild handling for saved REBUILD */ - if (iter_meta->ssd_ondisk == max_counter_val && - mc->scm_status != BIOC_SDREBUILD) + if (!rebuild && !invalidate) vol->extents[index].state = HR_EXT_ONLINE; + else if (rebuild && !invalidate) + vol->extents[index].state = HR_EXT_REBUILD; else vol->extents[index].state = HR_EXT_INVALID; } @@ -223,8 +240,7 @@ static bool meta_softraid_compare_uuids(const void *m1_v, const void *m2_v) { const struct sr_metadata *m1 = m1_v; const struct sr_metadata *m2 = m2_v; - if (memcmp(&m1->ssdi.ssd_uuid, &m2->ssdi.ssd_uuid, - SR_UUID_MAX) == 0) + if (memcmp(&m1->ssdi.ssd_uuid, &m2->ssdi.ssd_uuid, SR_UUID_MAX) == 0) return true; return false; @@ -245,7 +261,14 @@ static errno_t meta_softraid_save(hr_volume_t *vol, bool with_state_callback) { HR_DEBUG("%s()", __func__); - return ENOTSUP; + fibril_rwlock_read_lock(&vol->extents_lock); + + for (size_t i = 0; i < vol->extent_no; i++) + meta_softraid_save_ext(vol, i, with_state_callback); + + fibril_rwlock_read_unlock(&vol->extents_lock); + + return EOK; } static errno_t meta_softraid_save_ext(hr_volume_t *vol, size_t ext_idx, @@ -253,7 +276,46 @@ static errno_t meta_softraid_save_ext(hr_volume_t *vol, size_t ext_idx, { HR_DEBUG("%s()", __func__); - return ENOTSUP; + assert(fibril_rwlock_is_locked(&vol->extents_lock)); + + void *md_block = hr_calloc_waitok(1, vol->bsize * SR_META_SIZE); + + struct sr_metadata *md = vol->in_mem_md; + struct sr_meta_chunk *mc = + ((struct sr_meta_chunk *)(md + 1)) + ext_idx; + + hr_extent_t *ext = &vol->extents[ext_idx]; + + fibril_rwlock_read_lock(&vol->states_lock); + hr_ext_state_t s = ext->state; + fibril_rwlock_read_unlock(&vol->states_lock); + + if (s != HR_EXT_ONLINE && s != HR_EXT_REBUILD) { + return EINVAL; + } + + fibril_mutex_lock(&vol->md_lock); + + if (s == HR_EXT_REBUILD) { + md->ssd_rebuild = vol->rebuild_blk; + mc->scm_status = BIOC_SDREBUILD; + } else { + md->ssd_rebuild = 0; + mc->scm_status = BIOC_SDONLINE; + } + + meta_softraid_encode(md, md_block); + errno_t rc = meta_softraid_write_block(ext->svc_id, md_block); + if (rc != EOK && with_state_callback) + vol->hr_ops.ext_state_cb(vol, ext_idx, rc); + + fibril_mutex_unlock(&vol->md_lock); + + if (with_state_callback) + vol->hr_ops.vol_state_eval(vol); + + free(md_block); + return EOK; } static const char *meta_softraid_get_devname(const void *md_v) @@ -315,15 +377,99 @@ static void *meta_softraid_alloc_struct(void) return calloc(1, SR_META_SIZE * DEV_BSIZE); } -#if 0 static void meta_softraid_encode(void *md_v, void *block) { HR_DEBUG("%s()", __func__); - (void)md_v; - (void)block; + errno_t rc = EOK; + struct sr_metadata *md = md_v; + uint8_t md5_hash[16]; + + struct sr_metadata *scratch_md = + hr_calloc_waitok(1, SR_META_SIZE * DEV_BSIZE); + + scratch_md->ssdi.ssd_magic = host2uint64_t_le(md->ssdi.ssd_magic); + scratch_md->ssdi.ssd_version = host2uint32_t_le(md->ssdi.ssd_version); + scratch_md->ssdi.ssd_vol_flags = + host2uint32_t_le(md->ssdi.ssd_vol_flags); + memcpy(&scratch_md->ssdi.ssd_uuid, &md->ssdi.ssd_uuid, SR_UUID_MAX); + scratch_md->ssdi.ssd_chunk_no = + host2uint32_t_le(md->ssdi.ssd_chunk_no); + scratch_md->ssdi.ssd_chunk_id = + host2uint32_t_le(md->ssdi.ssd_chunk_id); + scratch_md->ssdi.ssd_opt_no = host2uint32_t_le(md->ssdi.ssd_opt_no); + scratch_md->ssdi.ssd_secsize = host2uint32_t_le(md->ssdi.ssd_secsize); + scratch_md->ssdi.ssd_volid = host2uint32_t_le(md->ssdi.ssd_volid); + scratch_md->ssdi.ssd_level = host2uint32_t_le(md->ssdi.ssd_level); + scratch_md->ssdi.ssd_size = host2int64_t_le(md->ssdi.ssd_size); + memcpy(scratch_md->ssdi.ssd_vendor, md->ssdi.ssd_vendor, 8); + memcpy(scratch_md->ssdi.ssd_product, md->ssdi.ssd_product, 16); + memcpy(scratch_md->ssdi.ssd_revision, md->ssdi.ssd_revision, 4); + scratch_md->ssdi.ssd_strip_size = + host2uint32_t_le(md->ssdi.ssd_strip_size); + rc = create_hash((const uint8_t *)&scratch_md->ssdi, + sizeof(struct sr_meta_invariant), md5_hash, HASH_MD5); + assert(rc == EOK); + memcpy(scratch_md->ssd_checksum, md5_hash, MD5_DIGEST_LENGTH); + + memcpy(scratch_md->ssd_devname, md->ssd_devname, 32); + + scratch_md->ssd_meta_flags = host2uint32_t_le(md->ssd_meta_flags); + scratch_md->ssd_data_blkno = host2uint32_t_le(md->ssd_data_blkno); + scratch_md->ssd_ondisk = host2uint64_t_le(md->ssd_ondisk); + scratch_md->ssd_rebuild = host2int64_t_le(md->ssd_rebuild); + + struct sr_meta_chunk *scratch_mc = + (struct sr_meta_chunk *)(scratch_md + 1); + struct sr_meta_chunk *mc = (struct sr_meta_chunk *)(md + 1); + for (size_t i = 0; i < md->ssdi.ssd_chunk_no; i++, mc++, scratch_mc++) { + scratch_mc->scmi.scm_volid = + host2uint32_t_le(mc->scmi.scm_volid); + scratch_mc->scmi.scm_chunk_id = + host2uint32_t_le(mc->scmi.scm_chunk_id); + memcpy(scratch_mc->scmi.scm_devname, mc->scmi.scm_devname, 32); + scratch_mc->scmi.scm_size = host2int64_t_le(mc->scmi.scm_size); + scratch_mc->scmi.scm_coerced_size = + host2int64_t_le(mc->scmi.scm_coerced_size); + memcpy(&scratch_mc->scmi.scm_uuid, &mc->scmi.scm_uuid, + SR_UUID_MAX); + + rc = create_hash((const uint8_t *)&scratch_mc->scmi, + sizeof(struct sr_meta_chunk_invariant), md5_hash, HASH_MD5); + assert(rc == EOK); + + memcpy(scratch_mc->scm_checksum, md5_hash, + MD5_DIGEST_LENGTH); + scratch_mc->scm_status = host2uint32_t_le(mc->scm_status); + } + + struct sr_meta_opt_hdr *scratch_om = + (struct sr_meta_opt_hdr *)((u_int8_t *)(scratch_md + 1) + + sizeof(struct sr_meta_chunk) * md->ssdi.ssd_chunk_no); + struct sr_meta_opt_hdr *om = + (struct sr_meta_opt_hdr *)((u_int8_t *)(md + 1) + + sizeof(struct sr_meta_chunk) * md->ssdi.ssd_chunk_no); + for (size_t i = 0; i < md->ssdi.ssd_opt_no; i++) { + scratch_om->som_type = host2uint32_t_le(om->som_type); + scratch_om->som_length = host2uint32_t_le(om->som_length); + memcpy(scratch_om->som_checksum, om->som_checksum, + MD5_DIGEST_LENGTH); + + /* + * No need to do checksum, we don't support optional headers. + * Despite this, still load it the headers. + */ + + om = (struct sr_meta_opt_hdr *)((void *)om + + om->som_length); + scratch_om = (struct sr_meta_opt_hdr *)((void *)scratch_om + + om->som_length); + } + + memcpy(block, scratch_md, meta_softraid_get_size() * 512); + + free(scratch_md); } -#endif static errno_t meta_softraid_decode(const void *block, void *md_v) { @@ -395,11 +541,6 @@ static errno_t meta_softraid_decode(const void *block, void *md_v) memcpy(md->ssd_devname, scratch_md->ssd_devname, 32); md->ssd_meta_flags = uint32_t_le2host(scratch_md->ssd_meta_flags); - if (md->ssd_meta_flags & SR_META_DIRTY) { - HR_DEBUG("dirty metadata not supported\n"); - rc = EINVAL; - goto error; - } md->ssd_data_blkno = uint32_t_le2host(scratch_md->ssd_data_blkno); md->ssd_ondisk = uint64_t_le2host(scratch_md->ssd_ondisk); md->ssd_rebuild = int64_t_le2host(scratch_md->ssd_rebuild); @@ -513,7 +654,6 @@ static errno_t meta_softraid_get_block(service_id_t dev, void **rblock) return EOK; } -#if 0 static errno_t meta_softraid_write_block(service_id_t dev, const void *block) { HR_DEBUG("%s()", __func__); @@ -540,7 +680,6 @@ static errno_t meta_softraid_write_block(service_id_t dev, const void *block) return rc; } -#endif /** @} */ From 7ef5ea2b8c56e607db447f3f5ea93898cee9d2d8 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 30 Jun 2025 01:21:19 +0200 Subject: [PATCH 298/324] hr: encoding and saving MD metadata support --- uspace/srv/bd/hr/metadata/foreign/md/hr_md.c | 196 ++++++++++++------- uspace/srv/bd/hr/metadata/foreign/md/md_p.h | 59 +++++- 2 files changed, 184 insertions(+), 71 deletions(-) diff --git a/uspace/srv/bd/hr/metadata/foreign/md/hr_md.c b/uspace/srv/bd/hr/metadata/foreign/md/hr_md.c index e9cc551da8..afd64d92d8 100644 --- a/uspace/srv/bd/hr/metadata/foreign/md/hr_md.c +++ b/uspace/srv/bd/hr/metadata/foreign/md/hr_md.c @@ -54,10 +54,10 @@ /* not exposed */ static void *meta_md_alloc_struct(void); -/* static void meta_md_encode(void *, void *); */ +static void meta_md_encode(void *, void *); static errno_t meta_md_decode(const void *, void *); static errno_t meta_md_get_block(service_id_t, void **); -/* static errno_t meta_md_write_block(service_id_t, const void *); */ +static errno_t meta_md_write_block(service_id_t, const void *); static errno_t meta_md_probe(service_id_t, void **); static errno_t meta_md_init_vol2meta(hr_volume_t *); @@ -189,23 +189,39 @@ static errno_t meta_md_init_meta2vol(const list_t *list, hr_volume_t *vol) vol->strip_size = main_meta->chunksize * 512; - vol->in_mem_md = calloc(1, MD_SIZE * 512); + vol->in_mem_md = calloc(vol->extent_no, MD_SIZE * 512); if (vol->in_mem_md == NULL) return ENOMEM; - memcpy(vol->in_mem_md, main_meta, MD_SIZE * 512); + size_t i = 0; list_foreach(*list, link, struct dev_list_member, iter) { struct mdp_superblock_1 *iter_meta = iter->md; uint8_t index = iter_meta->dev_roles[iter_meta->dev_number]; + struct mdp_superblock_1 *p = (struct mdp_superblock_1 *) + (((char *)vol->in_mem_md) + MD_SIZE * 512 * index); + memcpy(p, iter_meta, MD_SIZE * 512); + vol->extents[index].svc_id = iter->svc_id; iter->fini = false; - if (iter_meta->events == max_events && index < vol->extent_no) + bool invalidate = false; + + if (iter_meta->events != max_events) + invalidate = true; + + if (iter_meta->feature_map & MD_DISK_SYNC) + invalidate = true; + + if (!invalidate) vol->extents[index].state = HR_EXT_ONLINE; else vol->extents[index].state = HR_EXT_INVALID; + + i++; + if (i == vol->extent_no) + break; } for (size_t i = 0; i < vol->extent_no; i++) { @@ -239,9 +255,11 @@ static void meta_md_inc_counter(hr_volume_t *vol) { fibril_mutex_lock(&vol->md_lock); - struct mdp_superblock_1 *md = vol->in_mem_md; - - md->events++; + for (size_t d = 0; d < vol->extent_no; d++) { + struct mdp_superblock_1 *md = (struct mdp_superblock_1 *) + (((uint8_t *)vol->in_mem_md) + MD_SIZE * 512 * d); + md->events++; + } fibril_mutex_unlock(&vol->md_lock); } @@ -250,7 +268,14 @@ static errno_t meta_md_save(hr_volume_t *vol, bool with_state_callback) { HR_DEBUG("%s()", __func__); - return ENOTSUP; + fibril_rwlock_read_lock(&vol->extents_lock); + + for (size_t i = 0; i < vol->extent_no; i++) + meta_md_save_ext(vol, i, with_state_callback); + + fibril_rwlock_read_unlock(&vol->extents_lock); + + return EOK; } static errno_t meta_md_save_ext(hr_volume_t *vol, size_t ext_idx, @@ -258,7 +283,46 @@ static errno_t meta_md_save_ext(hr_volume_t *vol, size_t ext_idx, { HR_DEBUG("%s()", __func__); - return ENOTSUP; + assert(fibril_rwlock_is_locked(&vol->extents_lock)); + + void *md_block = hr_calloc_waitok(1, MD_SIZE * 512); + + struct mdp_superblock_1 *md = (struct mdp_superblock_1 *) + (((uint8_t *)vol->in_mem_md) + MD_SIZE * 512 * ext_idx); + + hr_extent_t *ext = &vol->extents[ext_idx]; + + fibril_rwlock_read_lock(&vol->states_lock); + hr_ext_state_t s = ext->state; + fibril_rwlock_read_unlock(&vol->states_lock); + + if (s != HR_EXT_ONLINE && s != HR_EXT_REBUILD) { + return EINVAL; + } + + fibril_mutex_lock(&vol->md_lock); + + if (s == HR_EXT_REBUILD) { + md->resync_offset = vol->rebuild_blk; + md->feature_map = MD_DISK_SYNC; + } else { + md->resync_offset = 0; + md->feature_map = 0; + } + + meta_md_encode(md, md_block); + errno_t rc = meta_md_write_block(ext->svc_id, md_block); + if (rc != EOK && with_state_callback) + vol->hr_ops.ext_state_cb(vol, ext_idx, rc); + + fibril_mutex_unlock(&vol->md_lock); + + if (with_state_callback) + vol->hr_ops.vol_state_eval(vol); + + free(md_block); + + return EOK; } static const char *meta_md_get_devname(const void *md_v) @@ -352,14 +416,10 @@ static void meta_md_dump(const void *md_v) printf("dev_number: %" PRIu32 "\n", md->dev_number); - printf("cnt_corrected_read: %" PRIu32 "\n", md->cnt_corrected_read); - printf("device_uuid: "); bytefield_print(md->device_uuid, 16); printf("\n"); - printf("devflags: 0x%" PRIx8 "\n", md->devflags); - printf("events: %" PRIu64 "\n", md->events); if (md->resync_offset == ~(0ULL)) @@ -367,8 +427,6 @@ static void meta_md_dump(const void *md_v) else printf("resync_offset: %" PRIu64 "\n", md->resync_offset); - printf("sb_csum: 0x%" PRIx32 "\n", md->sb_csum); - printf("max_dev: %" PRIu32 "\n", md->max_dev); printf("dev_roles: "); @@ -386,15 +444,34 @@ static void *meta_md_alloc_struct(void) return calloc(1, MD_SIZE * 512); } -#if 0 static void meta_md_encode(void *md_v, void *block) { HR_DEBUG("%s()", __func__); - (void)md_v; - (void)block; + memcpy(block, md_v, meta_md_get_size() * 512); + + struct mdp_superblock_1 *md = block; + + md->magic = host2uint32_t_le(md->magic); + md->major_version = host2uint32_t_le(md->major_version); + md->feature_map = host2uint32_t_le(md->feature_map); + md->level = host2uint32_t_le(md->level); + md->layout = host2uint32_t_le(md->layout); + md->size = host2uint64_t_le(md->size); + md->chunksize = host2uint32_t_le(md->chunksize); + md->raid_disks = host2uint32_t_le(md->raid_disks); + md->data_offset = host2uint64_t_le(md->data_offset); + md->data_size = host2uint64_t_le(md->data_size); + md->super_offset = host2uint64_t_le(md->super_offset); + md->dev_number = host2uint32_t_le(md->dev_number); + md->events = host2uint64_t_le(md->events); + md->resync_offset = host2uint64_t_le(md->resync_offset); + md->max_dev = host2uint32_t_le(md->max_dev); + for (uint32_t d = 0; d < md->max_dev; d++) + md->dev_roles[d] = host2uint16_t_le(md->dev_roles[d]); + + md->sb_csum = calc_sb_1_csum(md); } -#endif static errno_t meta_md_decode(const void *block, void *md_v) { @@ -403,39 +480,39 @@ static errno_t meta_md_decode(const void *block, void *md_v) errno_t rc = EOK; struct mdp_superblock_1 *md = md_v; - struct mdp_superblock_1 *scratch_md = meta_md_alloc_struct(); - if (scratch_md == NULL) - return ENOMEM; - - memcpy(scratch_md, block, meta_md_get_size() * 512); - - md->magic = uint32_t_le2host(scratch_md->magic); + /* + * Do in-place decoding to cpu byte order. + * We do it like this because: + * 1) we do not know what is after the 256 bytes + * of the struct, so we write back what was there + * previously, + * 2) we do not want to deal unused fields such + * as unions and so on. + */ + memcpy(md, block, meta_md_get_size() * 512); + + md->magic = uint32_t_le2host(md->magic); if (md->magic != MD_MAGIC) { rc = EINVAL; goto error; } - md->major_version = uint32_t_le2host(scratch_md->major_version); + md->major_version = uint32_t_le2host(md->major_version); if (md->major_version != 1) { HR_DEBUG("unsupported metadata version\n"); rc = EINVAL; goto error; } - md->feature_map = uint32_t_le2host(scratch_md->feature_map); + md->feature_map = uint32_t_le2host(md->feature_map); + /* XXX: do not even support MD_DISK_SYNC here */ if (md->feature_map != 0x0) { HR_DEBUG("unsupported feature map bits\n"); rc = EINVAL; goto error; } - memcpy(md->set_uuid, scratch_md->set_uuid, 16); - - memcpy(md->set_name, scratch_md->set_name, 32); - - md->ctime = uint64_t_le2host(scratch_md->ctime); - - md->level = uint32_t_le2host(scratch_md->level); + md->level = uint32_t_le2host(md->level); switch (md->level) { case 0: case 1: @@ -448,7 +525,7 @@ static errno_t meta_md_decode(const void *block, void *md_v) goto error; } - md->layout = uint32_t_le2host(scratch_md->layout); + md->layout = uint32_t_le2host(md->layout); if (md->level == 5) { switch (md->layout) { case ALGORITHM_LEFT_ASYMMETRIC: @@ -468,69 +545,50 @@ static errno_t meta_md_decode(const void *block, void *md_v) } } - md->size = uint64_t_le2host(scratch_md->size); + md->size = uint64_t_le2host(md->size); - md->chunksize = uint32_t_le2host(scratch_md->chunksize); + md->chunksize = uint32_t_le2host(md->chunksize); - md->raid_disks = uint32_t_le2host(scratch_md->raid_disks); + md->raid_disks = uint32_t_le2host(md->raid_disks); if (md->raid_disks > HR_MAX_EXTENTS) { rc = EINVAL; goto error; } - md->data_offset = uint64_t_le2host(scratch_md->data_offset); + md->data_offset = uint64_t_le2host(md->data_offset); - md->data_size = uint64_t_le2host(scratch_md->data_size); + md->data_size = uint64_t_le2host(md->data_size); if (md->data_size != md->size) { rc = EINVAL; goto error; } - md->super_offset = uint64_t_le2host(scratch_md->super_offset); + md->super_offset = uint64_t_le2host(md->super_offset); if (md->super_offset != MD_OFFSET) { rc = EINVAL; goto error; } - md->dev_number = uint32_t_le2host(scratch_md->dev_number); - - md->cnt_corrected_read = - uint32_t_le2host(scratch_md->cnt_corrected_read); - - memcpy(md->device_uuid, scratch_md->device_uuid, 16); - - md->devflags = scratch_md->devflags; + md->dev_number = uint32_t_le2host(md->dev_number); - md->bblog_shift = scratch_md->bblog_shift; + md->events = uint64_t_le2host(md->events); - md->bblog_size = uint16_t_le2host(scratch_md->bblog_size); - - md->bblog_offset = uint32_t_le2host(scratch_md->bblog_offset); - - md->utime = uint64_t_le2host(scratch_md->utime); - - md->events = uint64_t_le2host(scratch_md->events); - - md->resync_offset = uint64_t_le2host(scratch_md->resync_offset); - if (md->resync_offset != ~(0ULL)) { + md->resync_offset = uint64_t_le2host(md->resync_offset); + if (md->feature_map == 0 && md->resync_offset != ~(0ULL)) { rc = EINVAL; goto error; } - md->sb_csum = uint32_t_le2host(scratch_md->sb_csum); - - md->max_dev = uint32_t_le2host(scratch_md->max_dev); + md->max_dev = uint32_t_le2host(md->max_dev); if (md->max_dev > 256 + 128) { rc = EINVAL; goto error; } for (uint32_t d = 0; d < md->max_dev; d++) - md->dev_roles[d] = uint16_t_le2host(scratch_md->dev_roles[d]); + md->dev_roles[d] = uint16_t_le2host(md->dev_roles[d]); error: - free(scratch_md); - return rc; } @@ -574,7 +632,6 @@ static errno_t meta_md_get_block(service_id_t dev, void **rblock) return EOK; } -#if 0 static errno_t meta_md_write_block(service_id_t dev, const void *block) { HR_DEBUG("%s()", __func__); @@ -601,7 +658,6 @@ static errno_t meta_md_write_block(service_id_t dev, const void *block) return rc; } -#endif /** @} */ diff --git a/uspace/srv/bd/hr/metadata/foreign/md/md_p.h b/uspace/srv/bd/hr/metadata/foreign/md/md_p.h index 64492d5165..c8c0331b3e 100644 --- a/uspace/srv/bd/hr/metadata/foreign/md/md_p.h +++ b/uspace/srv/bd/hr/metadata/foreign/md/md_p.h @@ -33,6 +33,8 @@ typedef uint8_t __u8; #define MD_MAGIC 0xa92b4efc +#define MD_DISK_SYNC 2 + /* * The version-1 superblock : * All numeric fields are little-endian. @@ -129,11 +131,66 @@ struct mdp_superblock_1 { __le16 dev_roles[]; /* role in array, or 0xffff for a spare, or 0xfffe for faulty */ }; -/* from mdadm.h */ +/* + * mdadm - manage Linux "md" devices aka RAID arrays. + * + * Copyright (C) 2001-2016 Neil Brown + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Neil Brown + * Email: + */ + +/* from mdadm - mdadm.h*/ #define ALGORITHM_LEFT_ASYMMETRIC 0 #define ALGORITHM_RIGHT_ASYMMETRIC 1 #define ALGORITHM_LEFT_SYMMETRIC 2 +/* from mdadm - super1.c */ +static inline unsigned int calc_sb_1_csum(struct mdp_superblock_1 * sb) +{ + unsigned int disk_csum, csum; + unsigned long long newcsum; + int size = sizeof(*sb) + uint32_t_le2host(sb->max_dev)*2; + unsigned int *isuper = (unsigned int *)sb; + +/* make sure I can count... */ + if (offsetof(struct mdp_superblock_1,data_offset) != 128 || + offsetof(struct mdp_superblock_1, utime) != 192 || + sizeof(struct mdp_superblock_1) != 256) { + fprintf(stderr, "WARNING - superblock isn't sized correctly\n"); + } + + disk_csum = sb->sb_csum; + sb->sb_csum = 0; + newcsum = 0; + for (; size >= 4; size -= 4) { + newcsum += uint32_t_le2host(*isuper); + isuper++; + } + + if (size == 2) + newcsum += uint32_t_le2host(*(unsigned short*) isuper); + + csum = (newcsum & 0xffffffff) + (newcsum >> 32); + sb->sb_csum = disk_csum; + return host2uint32_t_le(csum); +} + #endif /** @} From 640250b3b42bbd66ee02c32d6221618976e46f0e Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 30 Jun 2025 01:28:19 +0200 Subject: [PATCH 299/324] hr: metadata/md: cstyle for MD metadata header --- uspace/srv/bd/hr/metadata/foreign/md/md_p.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/uspace/srv/bd/hr/metadata/foreign/md/md_p.h b/uspace/srv/bd/hr/metadata/foreign/md/md_p.h index c8c0331b3e..7899d971ba 100644 --- a/uspace/srv/bd/hr/metadata/foreign/md/md_p.h +++ b/uspace/srv/bd/hr/metadata/foreign/md/md_p.h @@ -155,21 +155,21 @@ struct mdp_superblock_1 { * Email: */ -/* from mdadm - mdadm.h*/ +/* from mdadm - mdadm.h */ #define ALGORITHM_LEFT_ASYMMETRIC 0 #define ALGORITHM_RIGHT_ASYMMETRIC 1 #define ALGORITHM_LEFT_SYMMETRIC 2 /* from mdadm - super1.c */ -static inline unsigned int calc_sb_1_csum(struct mdp_superblock_1 * sb) +static inline unsigned int calc_sb_1_csum(struct mdp_superblock_1 *sb) { unsigned int disk_csum, csum; unsigned long long newcsum; - int size = sizeof(*sb) + uint32_t_le2host(sb->max_dev)*2; + int size = sizeof(*sb) + uint32_t_le2host(sb->max_dev) * 2; unsigned int *isuper = (unsigned int *)sb; -/* make sure I can count... */ - if (offsetof(struct mdp_superblock_1,data_offset) != 128 || + /* make sure I can count... */ + if (offsetof(struct mdp_superblock_1, data_offset) != 128 || offsetof(struct mdp_superblock_1, utime) != 192 || sizeof(struct mdp_superblock_1) != 256) { fprintf(stderr, "WARNING - superblock isn't sized correctly\n"); @@ -184,7 +184,7 @@ static inline unsigned int calc_sb_1_csum(struct mdp_superblock_1 * sb) } if (size == 2) - newcsum += uint32_t_le2host(*(unsigned short*) isuper); + newcsum += uint32_t_le2host(*(unsigned short *) isuper); csum = (newcsum & 0xffffffff) + (newcsum >> 32); sb->sb_csum = disk_csum; From 95ca19d9a396dba7514044b52dced76cde943fe3 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 30 Jun 2025 11:31:21 +0200 Subject: [PATCH 300/324] hr: add --read-only volume flag --- uspace/app/hrctl/hrctl.c | 77 ++++++++++++++++++++++++++-------- uspace/lib/device/include/hr.h | 7 +++- uspace/lib/device/src/hr.c | 12 ++++++ uspace/srv/bd/hr/hr.c | 5 ++- uspace/srv/bd/hr/raid0.c | 3 ++ uspace/srv/bd/hr/raid1.c | 5 +++ uspace/srv/bd/hr/raid5.c | 5 +++ uspace/srv/bd/hr/util.c | 19 +++++---- uspace/srv/bd/hr/util.h | 2 +- uspace/srv/bd/hr/var.h | 1 + 10 files changed, 107 insertions(+), 29 deletions(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index d8533f8fb7..c55d8e858c 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -54,8 +54,8 @@ static errno_t get_vol_configs_from_sif(const char *, hr_config_t **, size_t *); static int create_from_config(hr_t *, const char *, uint8_t); static int create_from_argv(hr_t *, int, char **, uint8_t); static int handle_create(hr_t *, int, char **); -static int assemble_from_config(hr_t *, const char *); -static int assemble_from_argv(hr_t *, int, char **); +static int assemble_from_config(hr_t *, const char *, uint8_t); +static int assemble_from_argv(hr_t *, int, char **, uint8_t); static int handle_assemble(hr_t *, int, char **); static int handle_disassemble(hr_t *, int, char **); static int handle_modify(hr_t *, int, char **); @@ -69,13 +69,13 @@ static const char usage_str[] = "Options:\n" " -h, --help Display this message and exit.\n" "\n" - " -c, --create [--no_meta] Create a volume, options:\n" + " -c, --create [--no-meta] [--read-only] Create a volume, options:\n" " name {-l , --level level} device... manual device specification, or\n" " -f configuration.sif create from configuration file.\n" "\n" " -a, --assemble Assemble volume(s), options:\n" - " [device...] manual device specification, or\n" - " [-f configuration.sif] assemble from configuration file, or\n" + " [[--read-only] device...] manual device specification, or\n" + " [[--read-only] -f configuration.sif] assemble from configuration file, or\n" " no option is automatic assembly.\n" "\n" " -d, --disassemble Deactivate/disassemble, options:\n" @@ -107,7 +107,7 @@ static const char usage_str[] = "\t\thrctl -s\n" "\n" "Notes:\n" - " Add --no_meta after --create to disable storing on-disk metadata.\n" + " Add --no-meta after --create to disable storing on-disk metadata.\n" " Simulating an extent failure with -m volume -f index is dangerous. It marks\n" " metadata as dirty in other healthy extents, and zeroes out the superblock\n" " on the specified extent.\n" @@ -444,20 +444,41 @@ static int create_from_argv(hr_t *hr, int argc, char **argv, uint8_t vol_flags) return EXIT_FAILURE; } +static bool try_to_get_additional_flags(int argc, char **argv, + uint8_t test_flags, uint8_t *flags) +{ + if (test_flags & HR_VOL_FLAG_NOOP_META) { + if (str_cmp(argv[optind], "--no-meta") == 0) { + *flags |= HR_VOL_FLAG_NOOP_META; + optind++; + return true; + } + } + + if (test_flags & HR_VOL_FLAG_READ_ONLY) { + if (str_cmp(argv[optind], "--read-only") == 0) { + *flags |= HR_VOL_FLAG_READ_ONLY; + optind++; + return true; + } + } + + return false; +} + static int handle_create(hr_t *hr, int argc, char **argv) { int rc; - uint8_t vol_flags = 0; + uint8_t vflags = 0; if (optind >= argc) { printf(NAME ": no arguments to --create\n"); return EXIT_FAILURE; } - if (str_cmp(argv[optind], "--no_meta") == 0) { - vol_flags |= HR_VOL_FLAG_NOOP_META; - optind++; - } + uint8_t test_flags = HR_VOL_FLAG_NOOP_META | HR_VOL_FLAG_READ_ONLY; + while (try_to_get_additional_flags(argc, argv, test_flags, &vflags)) + ; if (str_cmp(argv[optind], "-f") == 0) { optind++; @@ -473,15 +494,16 @@ static int handle_create(hr_t *hr, int argc, char **argv) return EXIT_FAILURE; } - rc = create_from_config(hr, config_path, vol_flags); + rc = create_from_config(hr, config_path, vflags); } else { - rc = create_from_argv(hr, argc, argv, vol_flags); + rc = create_from_argv(hr, argc, argv, vflags); } return rc; } -static int assemble_from_config(hr_t *hr, const char *config_path) +static int assemble_from_config(hr_t *hr, const char *config_path, + uint8_t vflags) { hr_config_t *vol_configs = NULL; size_t vol_count = 0; @@ -495,6 +517,7 @@ static int assemble_from_config(hr_t *hr, const char *config_path) size_t cnt = 0; for (size_t i = 0; i < vol_count; i++) { size_t tmpcnt = 0; + vol_configs[i].vol_flags = vflags; (void)hr_assemble(hr, &vol_configs[i], &tmpcnt); cnt += tmpcnt; } @@ -505,7 +528,7 @@ static int assemble_from_config(hr_t *hr, const char *config_path) return EXIT_SUCCESS; } -static int assemble_from_argv(hr_t *hr, int argc, char **argv) +static int assemble_from_argv(hr_t *hr, int argc, char **argv, uint8_t vflags) { hr_config_t *vol_config = calloc(1, sizeof(hr_config_t)); if (vol_config == NULL) { @@ -513,6 +536,8 @@ static int assemble_from_argv(hr_t *hr, int argc, char **argv) return ENOMEM; } + vol_config->vol_flags = vflags; + errno_t rc = fill_config_devs(argc, argv, vol_config); if (rc != EOK) goto error; @@ -550,6 +575,14 @@ static int handle_assemble(hr_t *hr, int argc, char **argv) return EXIT_SUCCESS; } + uint8_t vflags = 0; + uint8_t test_flags = HR_VOL_FLAG_NOOP_META | HR_VOL_FLAG_READ_ONLY; + while (try_to_get_additional_flags(argc, argv, test_flags, &vflags)) + ; + + if (test_flags & HR_VOL_FLAG_NOOP_META) + printf(NAME ": assembling, --no-meta flag will be ignored\n"); + if (str_cmp(argv[optind], "-f") == 0) { if (++optind >= argc) { printf(NAME ": not enough arguments\n"); @@ -562,9 +595,9 @@ static int handle_assemble(hr_t *hr, int argc, char **argv) return EXIT_FAILURE; } - rc = assemble_from_config(hr, config_path); + rc = assemble_from_config(hr, config_path, vflags); } else { - rc = assemble_from_argv(hr, argc, argv); + rc = assemble_from_argv(hr, argc, argv, vflags); } return rc; @@ -657,6 +690,16 @@ static errno_t print_vol_info(hr_vol_info_t *info) printf("| metadata type: %s\n", hr_get_metadata_type_str(info->meta_type)); + + printf("| vflags: "); + for (size_t v = 0; v < HR_VOL_FLAG_COUNT; v++) { + if (info->vflags & (1 << v)) { + printf("%s ", + hr_get_vol_flag_str(info->vflags & (1 << v))); + } + } + printf("\n"); + printf("| level: %s\n", hr_get_level_str(info->level)); if (info->layout != HR_LAYOUT_NONE) printf("| layout: %s\n", diff --git a/uspace/lib/device/include/hr.h b/uspace/lib/device/include/hr.h index 8210a7bb40..3bc8bb9389 100644 --- a/uspace/lib/device/include/hr.h +++ b/uspace/lib/device/include/hr.h @@ -91,8 +91,10 @@ typedef enum { HR_METADATA_LAST_PLACEHOLDER } hr_metadata_type_t; +#define HR_VOL_FLAG_COUNT 2 typedef enum hr_vol_flag { - HR_VOL_FLAG_NOOP_META = 0x01 + HR_VOL_FLAG_NOOP_META = 0x01, + HR_VOL_FLAG_READ_ONLY = 0x02 } hr_vol_flag_t; typedef struct hr { @@ -132,7 +134,7 @@ typedef struct hr_vol_info { hr_vol_state_t state; hr_layout_t layout; hr_metadata_type_t meta_type; - /* TODO: add rebuild pos */ + uint8_t vflags; } hr_vol_info_t; extern errno_t hr_sess_init(hr_t **); @@ -151,6 +153,7 @@ extern const char *hr_get_ext_state_str(hr_ext_state_t); extern const char *hr_get_layout_str(hr_layout_t); extern const char *hr_get_level_str(hr_level_t); extern const char *hr_get_metadata_type_str(hr_metadata_type_t); +extern const char *hr_get_vol_flag_str(hr_vol_flag_t); #endif diff --git a/uspace/lib/device/src/hr.c b/uspace/lib/device/src/hr.c index 619504749d..f770e855ee 100644 --- a/uspace/lib/device/src/hr.c +++ b/uspace/lib/device/src/hr.c @@ -560,5 +560,17 @@ const char *hr_get_metadata_type_str(hr_metadata_type_t type) } } +const char *hr_get_vol_flag_str(hr_vol_flag_t flag) +{ + switch (flag) { + case HR_VOL_FLAG_NOOP_META: + return "--no-meta"; + case HR_VOL_FLAG_READ_ONLY: + return "--read-only"; + default: + return "Invalid flag"; + } +} + /** @} */ diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 6648212705..e9bbcba274 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -136,8 +136,8 @@ static void hr_create_srv(ipc_call_t *icall) else meta_type = HR_METADATA_NATIVE; - printf("creating with type %d\n", meta_type); - rc = hr_create_vol_struct(&vol, cfg->level, cfg->devname, meta_type); + rc = hr_create_vol_struct(&vol, cfg->level, cfg->devname, meta_type, + cfg->vol_flags); if (rc != EOK) { free(cfg); async_answer_0(icall, rc); @@ -530,6 +530,7 @@ static void hr_get_vol_info_srv(ipc_call_t *icall) info.layout = vol->layout; info.meta_type = vol->meta_ops->get_type(); memcpy(info.devname, vol->devname, HR_DEVNAME_LEN); + info.vflags = vol->vflags; if (!async_data_read_receive(&call, &size)) { rc = EREFUSED; diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index e5e1ce06ba..67b77ec96e 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -255,6 +255,9 @@ static errno_t hr_raid0_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba, if (size < cnt * vol->bsize) return EINVAL; + if (vol->vflags & HR_VOL_FLAG_READ_ONLY && type == HR_BD_WRITE) + return ENOTSUP; + fibril_rwlock_read_lock(&vol->states_lock); if (vol->state != HR_VOL_OPTIMAL) { fibril_rwlock_read_unlock(&vol->states_lock); diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 9d832b05a0..3fc64eefd3 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -277,6 +277,9 @@ static errno_t hr_raid1_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, { hr_volume_t *vol = bd->srvs->sarg; + if (vol->vflags & HR_VOL_FLAG_READ_ONLY) + return ENOTSUP; + return hr_raid1_bd_op(HR_BD_WRITE, vol, ba, cnt, NULL, data, size); } @@ -454,6 +457,8 @@ static errno_t hr_raid1_rebuild(void *arg) hr_extent_t *rebuild_ext = NULL; errno_t rc; + if (vol->vflags & HR_VOL_FLAG_READ_ONLY) + return ENOTSUP; if (!(vol->meta_ops->get_flags() & HR_METADATA_ALLOW_REBUILD)) return ENOTSUP; diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 406851b7fd..866bbdf886 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -383,6 +383,9 @@ static errno_t hr_raid5_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, if (size < cnt * vol->bsize) return EINVAL; + if (vol->vflags & HR_VOL_FLAG_READ_ONLY) + return ENOTSUP; + fibril_rwlock_read_lock(&vol->states_lock); hr_vol_state_t vol_state = vol->state; fibril_rwlock_read_unlock(&vol->states_lock); @@ -716,6 +719,8 @@ static errno_t hr_raid5_rebuild(void *arg) size_t rebuild_idx; void *buf = NULL, *xorbuf = NULL; + if (vol->vflags & HR_VOL_FLAG_READ_ONLY) + return ENOTSUP; if (!(vol->meta_ops->get_flags() & HR_METADATA_ALLOW_REBUILD)) return ENOTSUP; diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 69c7ff4435..883bd4bcab 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -64,7 +64,7 @@ static void block_fini_dev_list(list_t *); static errno_t hr_util_get_matching_md_svcs_list(list_t *, list_t *, service_id_t, hr_metadata_type_t, void *); static errno_t hr_util_assemble_from_matching_list(list_t *, - hr_metadata_type_t); + hr_metadata_type_t, uint8_t); static errno_t hr_fill_svcs_list_from_cfg(hr_config_t *, list_t *); static errno_t hr_swap_hs(hr_volume_t *, size_t, size_t); @@ -101,7 +101,7 @@ void *hr_calloc_waitok(size_t nmemb, size_t size) } errno_t hr_create_vol_struct(hr_volume_t **rvol, hr_level_t level, - const char *devname, hr_metadata_type_t metadata_type) + const char *devname, hr_metadata_type_t metadata_type, uint8_t vflags) { HR_DEBUG("%s()", __func__); @@ -114,6 +114,8 @@ errno_t hr_create_vol_struct(hr_volume_t **rvol, hr_level_t level, str_cpy(vol->devname, HR_DEVNAME_LEN, devname); vol->level = level; + vol->vflags = vflags; + vol->meta_ops = hr_get_meta_type_ops(metadata_type); uint8_t meta_flags = vol->meta_ops->get_flags(); @@ -830,7 +832,7 @@ static errno_t hr_util_get_matching_md_svcs_list(list_t *rlist, list_t *list, } static errno_t hr_util_assemble_from_matching_list(list_t *list, - hr_metadata_type_t type) + hr_metadata_type_t type, uint8_t vflags) { HR_DEBUG("%s()", __func__); @@ -846,7 +848,7 @@ static errno_t hr_util_assemble_from_matching_list(list_t *list, const char *devname = meta_ops->get_devname(memb->md); hr_volume_t *vol; - rc = hr_create_vol_struct(&vol, level, devname, type); + rc = hr_create_vol_struct(&vol, level, devname, type, vflags); if (rc != EOK) return rc; @@ -912,13 +914,16 @@ errno_t hr_util_try_assemble(hr_config_t *cfg, size_t *rassembled_cnt) size_t asm_cnt = 0; errno_t rc; list_t dev_id_list; + uint8_t vflags = 0; list_initialize(&dev_id_list); - if (cfg == NULL) + if (cfg == NULL) { rc = hr_fill_disk_part_svcs_list(&dev_id_list); - else + } else { rc = hr_fill_svcs_list_from_cfg(cfg, &dev_id_list); + vflags = cfg->vol_flags; + } if (rc != EOK) goto error; @@ -985,7 +990,7 @@ errno_t hr_util_try_assemble(hr_config_t *cfg, size_t *rassembled_cnt) } rc = hr_util_assemble_from_matching_list(&matching_svcs_list, - type); + type, vflags); switch (rc) { case EOK: asm_cnt++; diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index 7ea9b89653..21d00f0de6 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -83,7 +83,7 @@ extern void *hr_calloc_waitok(size_t, size_t) __attribute__((malloc)); extern errno_t hr_create_vol_struct(hr_volume_t **, hr_level_t, const char *, - hr_metadata_type_t); + hr_metadata_type_t, uint8_t); extern void hr_destroy_vol_struct(hr_volume_t *); extern errno_t hr_get_volume_svcs(size_t *, service_id_t **); extern hr_volume_t *hr_get_volume(service_id_t); diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index 9a2d11b79b..cc99bdde42 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -117,6 +117,7 @@ typedef struct hr_volume { _Atomic uint64_t rebuild_blk; /* rebuild position */ _Atomic int open_cnt; /* open/close() counter */ hr_vol_state_t state; /* volume state */ + uint8_t vflags; } hr_volume_t; typedef enum { From 059885cb7b988a4bb920cfcaed111b6cae26758a Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 30 Jun 2025 12:55:31 +0200 Subject: [PATCH 301/324] hr: metadata/softraid: fix and allow rebuild --- .../metadata/foreign/softraid/hr_softraid.c | 24 +++++++++++-------- .../hr/metadata/foreign/softraid/softraid.c | 1 + 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c index 44ab2298aa..e62c9a8bde 100644 --- a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c +++ b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c @@ -181,7 +181,7 @@ static errno_t meta_softraid_init_meta2vol(const list_t *list, hr_volume_t *vol) return ENOMEM; memcpy(vol->in_mem_md, main_meta, SR_META_SIZE * DEV_BSIZE); - bool rebuild = false; + bool rebuild_set = false; list_foreach(*list, link, struct dev_list_member, iter) { struct sr_metadata *iter_meta = iter->md; @@ -194,6 +194,7 @@ static errno_t meta_softraid_init_meta2vol(const list_t *list, hr_volume_t *vol) ((struct sr_meta_chunk *)(main_meta + 1)) + index; bool invalidate = false; + bool rebuild_this_ext = false; if (iter_meta->ssd_meta_flags & SR_META_DIRTY) invalidate = true; @@ -201,18 +202,19 @@ static errno_t meta_softraid_init_meta2vol(const list_t *list, hr_volume_t *vol) invalidate = true; if (mc->scm_status == BIOC_SDREBUILD && !invalidate) { - if (rebuild) { + if (rebuild_set) { HR_DEBUG("only 1 rebuilt extent allowed"); rc = EINVAL; goto error; } - rebuild = true; + rebuild_set = true; + rebuild_this_ext = true; vol->rebuild_blk = iter_meta->ssd_rebuild; } - if (!rebuild && !invalidate) + if (!rebuild_this_ext && !invalidate) vol->extents[index].state = HR_EXT_ONLINE; - else if (rebuild && !invalidate) + else if (rebuild_this_ext && !invalidate) vol->extents[index].state = HR_EXT_REBUILD; else vol->extents[index].state = HR_EXT_INVALID; @@ -296,13 +298,13 @@ static errno_t meta_softraid_save_ext(hr_volume_t *vol, size_t ext_idx, fibril_mutex_lock(&vol->md_lock); - if (s == HR_EXT_REBUILD) { - md->ssd_rebuild = vol->rebuild_blk; + md->ssd_rebuild = vol->rebuild_blk; + md->ssdi.ssd_chunk_id = ext_idx; + + if (s == HR_EXT_REBUILD) mc->scm_status = BIOC_SDREBUILD; - } else { - md->ssd_rebuild = 0; + else mc->scm_status = BIOC_SDONLINE; - } meta_softraid_encode(md, md_block); errno_t rc = meta_softraid_write_block(ext->svc_id, md_block); @@ -355,6 +357,8 @@ static uint8_t meta_softraid_get_flags(void) { uint8_t flags = 0; + flags |= HR_METADATA_ALLOW_REBUILD; + return flags; } diff --git a/uspace/srv/bd/hr/metadata/foreign/softraid/softraid.c b/uspace/srv/bd/hr/metadata/foreign/softraid/softraid.c index 338bfd9eae..06becb926e 100644 --- a/uspace/srv/bd/hr/metadata/foreign/softraid/softraid.c +++ b/uspace/srv/bd/hr/metadata/foreign/softraid/softraid.c @@ -96,6 +96,7 @@ sr_meta_print(const struct sr_metadata *m) printf("\n"); printf("\tssd_meta_flags 0x%" PRIx32 "\n", m->ssd_meta_flags); printf("\tssd_ondisk %" PRId64 "\n", m->ssd_ondisk); + printf("\tssd_rebuild %" PRId64 "\n", m->ssd_rebuild); mc = (struct sr_meta_chunk *)(m + 1); for (i = 0; i < m->ssdi.ssd_chunk_no; i++, mc++) { From d04a350aca941393e8dd4e7dd984deb53bff8df0 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 30 Jun 2025 13:09:46 +0200 Subject: [PATCH 302/324] hr: metadata/gmirror: fix setting extent states --- uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c index 3b0881a3b7..55dd041838 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c @@ -177,7 +177,7 @@ static errno_t meta_gmirror_init_meta2vol(const list_t *list, hr_volume_t *vol) return ENOMEM; memcpy(vol->in_mem_md, main_meta, sizeof(struct g_mirror_metadata)); - bool rebuild = false; + bool rebuild_set = false; uint8_t index = 0; list_foreach(*list, link, struct dev_list_member, iter) { @@ -191,6 +191,7 @@ static errno_t meta_gmirror_init_meta2vol(const list_t *list, hr_volume_t *vol) iter->fini = false; bool invalidate = false; + bool rebuild_this_ext = false; if (iter_meta->md_dflags & G_MIRROR_DISK_FLAG_DIRTY) invalidate = true; @@ -199,18 +200,19 @@ static errno_t meta_gmirror_init_meta2vol(const list_t *list, hr_volume_t *vol) if (iter_meta->md_dflags & G_MIRROR_DISK_FLAG_SYNCHRONIZING && !invalidate) { - if (rebuild) { + if (rebuild_set) { HR_DEBUG("only 1 rebuilt extent allowed"); rc = EINVAL; goto error; } - rebuild = true; + rebuild_set = true; + rebuild_this_ext = true; vol->rebuild_blk = iter_meta->md_sync_offset; } - if (!rebuild && !invalidate) + if (!rebuild_this_ext && !invalidate) vol->extents[index].state = HR_EXT_ONLINE; - else if (rebuild && !invalidate) + else if (rebuild_this_ext && !invalidate) vol->extents[index].state = HR_EXT_REBUILD; else vol->extents[index].state = HR_EXT_INVALID; From dcdb99082e1e6f56b22a07bc1682c1cc06e9fa94 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 30 Jun 2025 19:14:01 +0200 Subject: [PATCH 303/324] hr: metadata/md: have to take rebuild into account Even if not allowing rebuild operation to happen, we still must take rebuilt extents into account, because writes below the resync_offset must be done like in ONLINE state. --- uspace/srv/bd/hr/metadata/foreign/md/hr_md.c | 22 +++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/uspace/srv/bd/hr/metadata/foreign/md/hr_md.c b/uspace/srv/bd/hr/metadata/foreign/md/hr_md.c index afd64d92d8..24a74c2ae9 100644 --- a/uspace/srv/bd/hr/metadata/foreign/md/hr_md.c +++ b/uspace/srv/bd/hr/metadata/foreign/md/hr_md.c @@ -193,6 +193,7 @@ static errno_t meta_md_init_meta2vol(const list_t *list, hr_volume_t *vol) if (vol->in_mem_md == NULL) return ENOMEM; + bool rebuild_set = false; size_t i = 0; list_foreach(*list, link, struct dev_list_member, iter) { struct mdp_superblock_1 *iter_meta = iter->md; @@ -207,15 +208,26 @@ static errno_t meta_md_init_meta2vol(const list_t *list, hr_volume_t *vol) iter->fini = false; bool invalidate = false; + bool rebuild_this_ext = false; if (iter_meta->events != max_events) invalidate = true; - if (iter_meta->feature_map & MD_DISK_SYNC) - invalidate = true; + if (iter_meta->feature_map & MD_DISK_SYNC && !invalidate) { + if (rebuild_set) { + HR_DEBUG("only 1 rebuilt extent allowed"); + rc = EINVAL; + goto error; + } + rebuild_set = true; + rebuild_this_ext = true; + vol->rebuild_blk = iter_meta->resync_offset; + } - if (!invalidate) + if (!rebuild_this_ext && !invalidate) vol->extents[index].state = HR_EXT_ONLINE; + else if (rebuild_this_ext && !invalidate) + vol->extents[index].state = HR_EXT_REBUILD; else vol->extents[index].state = HR_EXT_INVALID; @@ -229,6 +241,7 @@ static errno_t meta_md_init_meta2vol(const list_t *list, hr_volume_t *vol) vol->extents[i].state = HR_EXT_MISSING; } +error: return rc; } @@ -505,8 +518,7 @@ static errno_t meta_md_decode(const void *block, void *md_v) } md->feature_map = uint32_t_le2host(md->feature_map); - /* XXX: do not even support MD_DISK_SYNC here */ - if (md->feature_map != 0x0) { + if (md->feature_map != 0x0 && md->feature_map != MD_DISK_SYNC) { HR_DEBUG("unsupported feature map bits\n"); rc = EINVAL; goto error; From 996d31acc0c6d09af6ff2425f7df18593ca1dc24 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Wed, 2 Jul 2025 22:43:58 +0200 Subject: [PATCH 304/324] hr: retire level specific add_hotspare() hr_ops_t --- uspace/srv/bd/hr/hr.c | 16 ++++++++++++---- uspace/srv/bd/hr/raid1.c | 11 ----------- uspace/srv/bd/hr/raid5.c | 11 ----------- uspace/srv/bd/hr/util.c | 6 ------ uspace/srv/bd/hr/var.h | 4 ---- 5 files changed, 12 insertions(+), 36 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index e9bbcba274..cde274a047 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -406,15 +406,23 @@ static void hr_add_hotspare_srv(ipc_call_t *icall) return; } - if (vol->hr_ops.add_hotspare == NULL) { - HR_NOTE("hotspare not supported on RAID level = %d, " - "metadata type = %s\n", vol->level, + if (vol->level == HR_LVL_0) { + HR_NOTE("hotspare not supported on RAID level = %s\n", + hr_get_level_str(vol->level)); + async_answer_0(icall, ENOTSUP); + return; + } + + if (!(vol->meta_ops->get_flags() & HR_METADATA_HOTSPARE_SUPPORT)) { + HR_NOTE("hotspare not supported on metadata type = %s\n", hr_get_metadata_type_str(vol->meta_ops->get_type())); async_answer_0(icall, ENOTSUP); return; } - rc = vol->hr_ops.add_hotspare(vol, hotspare); + rc = hr_util_add_hotspare(vol, hotspare); + + vol->hr_ops.vol_state_eval(vol); async_answer_0(icall, rc); } diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 3fc64eefd3..36b12ae1a9 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -132,17 +132,6 @@ errno_t hr_raid1_init(hr_volume_t *vol) return EOK; } -errno_t hr_raid1_add_hotspare(hr_volume_t *vol, service_id_t hotspare) -{ - HR_DEBUG("%s()", __func__); - - errno_t rc = hr_util_add_hotspare(vol, hotspare); - - hr_raid1_vol_state_eval(vol); - - return rc; -} - void hr_raid1_vol_state_eval(hr_volume_t *vol) { HR_DEBUG("%s()", __func__); diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 866bbdf886..38d375ce90 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -154,17 +154,6 @@ void hr_raid5_vol_state_eval(hr_volume_t *vol) hr_raid5_vol_state_eval_forced(vol); } -errno_t hr_raid5_add_hotspare(hr_volume_t *vol, service_id_t hotspare) -{ - HR_DEBUG("%s()", __func__); - - errno_t rc = hr_util_add_hotspare(vol, hotspare); - - hr_raid5_vol_state_eval(vol); - - return rc; -} - void hr_raid5_ext_state_cb(hr_volume_t *vol, size_t extent, errno_t rc) { HR_DEBUG("%s()", __func__); diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 883bd4bcab..cfefa1047b 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -118,8 +118,6 @@ errno_t hr_create_vol_struct(hr_volume_t **rvol, hr_level_t level, vol->meta_ops = hr_get_meta_type_ops(metadata_type); - uint8_t meta_flags = vol->meta_ops->get_flags(); - switch (level) { case HR_LVL_0: vol->hr_ops.create = hr_raid0_create; @@ -132,8 +130,6 @@ errno_t hr_create_vol_struct(hr_volume_t **rvol, hr_level_t level, vol->hr_ops.init = hr_raid1_init; vol->hr_ops.vol_state_eval = hr_raid1_vol_state_eval; vol->hr_ops.ext_state_cb = hr_raid1_ext_state_cb; - if (meta_flags & HR_METADATA_HOTSPARE_SUPPORT) - vol->hr_ops.add_hotspare = hr_raid1_add_hotspare; break; case HR_LVL_4: case HR_LVL_5: @@ -141,8 +137,6 @@ errno_t hr_create_vol_struct(hr_volume_t **rvol, hr_level_t level, vol->hr_ops.init = hr_raid5_init; vol->hr_ops.vol_state_eval = hr_raid5_vol_state_eval; vol->hr_ops.ext_state_cb = hr_raid5_ext_state_cb; - if (meta_flags & HR_METADATA_HOTSPARE_SUPPORT) - vol->hr_ops.add_hotspare = hr_raid5_add_hotspare; break; default: HR_DEBUG("unkown level: %d, aborting\n", vol->level); diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index cc99bdde42..c8ad629feb 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -65,7 +65,6 @@ typedef struct hr_superblock_ops hr_superblock_ops_t; typedef struct hr_ops { errno_t (*create)(hr_volume_t *); errno_t (*init)(hr_volume_t *); - errno_t (*add_hotspare)(hr_volume_t *, service_id_t); void (*vol_state_eval)(hr_volume_t *); void (*ext_state_cb)(hr_volume_t *, size_t, errno_t); } hr_ops_t; @@ -137,9 +136,6 @@ extern errno_t hr_raid0_init(hr_volume_t *); extern errno_t hr_raid1_init(hr_volume_t *); extern errno_t hr_raid5_init(hr_volume_t *); -extern errno_t hr_raid1_add_hotspare(hr_volume_t *, service_id_t); -extern errno_t hr_raid5_add_hotspare(hr_volume_t *, service_id_t); - extern void hr_raid0_vol_state_eval(hr_volume_t *); extern void hr_raid1_vol_state_eval(hr_volume_t *); extern void hr_raid5_vol_state_eval(hr_volume_t *); From 038a8d02379d91955e84721e50bc8951c9f79d4c Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Thu, 3 Jul 2025 16:52:15 +0200 Subject: [PATCH 305/324] hr: hr_client_conn(): return when no vol is found --- uspace/srv/bd/hr/hr.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index cde274a047..e9b3372a38 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -630,8 +630,10 @@ static void hr_client_conn(ipc_call_t *icall, void *arg) hr_ctl_conn(icall); } else { vol = hr_get_volume(svc_id); - if (vol == NULL) + if (vol == NULL) { async_answer_0(icall, ENOENT); + return; + } bd_conn(icall, &vol->hr_bds); } } From b247c7145535f828c4029dbc592e1daef51f4928 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Thu, 3 Jul 2025 19:09:13 +0200 Subject: [PATCH 306/324] hr: rename async handler --- uspace/srv/bd/hr/hr.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index e9b3372a38..56a63ebd77 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -60,7 +60,7 @@ static void hr_stop_all_srv(ipc_call_t *); static void hr_add_hotspare_srv(ipc_call_t *); static void hr_get_vol_states_srv(ipc_call_t *); static void hr_ctl_conn(ipc_call_t *); -static void hr_client_conn(ipc_call_t *, void *); +static void hr_call_handler(ipc_call_t *, void *); loc_srv_t *hr_srv; list_t hr_volumes; @@ -618,7 +618,7 @@ static void hr_ctl_conn(ipc_call_t *icall) * Distinguishes between control IPC and block device * IPC calls. */ -static void hr_client_conn(ipc_call_t *icall, void *arg) +static void hr_call_handler(ipc_call_t *icall, void *arg) { HR_DEBUG("%s()", __func__); @@ -653,7 +653,7 @@ int main(int argc, char **argv) fibril_rwlock_initialize(&hr_volumes_lock); list_initialize(&hr_volumes); - async_set_fallback_port_handler(hr_client_conn, NULL); + async_set_fallback_port_handler(hr_call_handler, NULL); rc = loc_server_register(NAME, &hr_srv); if (rc != EOK) { From 6aafb480111c5cc96fb85e470247a656a20f0613 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 4 Jul 2025 12:14:23 +0200 Subject: [PATCH 307/324] hr: rebuild: fix deadlock on extents_lock --- uspace/srv/bd/hr/hr.c | 8 +++++--- uspace/srv/bd/hr/raid1.c | 23 +++++++++++------------ uspace/srv/bd/hr/raid5.c | 2 ++ uspace/srv/bd/hr/util.c | 14 +++++++++----- 4 files changed, 27 insertions(+), 20 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 56a63ebd77..14871d101c 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -357,7 +357,7 @@ static void hr_fail_extent_srv(ipc_call_t *icall) return; } - fibril_rwlock_read_lock(&vol->extents_lock); + fibril_rwlock_write_lock(&vol->extents_lock); fibril_rwlock_write_lock(&vol->states_lock); hr_extent_t *ext = &vol->extents[extent_idx_to_fail]; @@ -367,17 +367,19 @@ static void hr_fail_extent_srv(ipc_call_t *icall) case HR_EXT_MISSING: case HR_EXT_FAILED: fibril_rwlock_write_unlock(&vol->states_lock); - fibril_rwlock_read_unlock(&vol->extents_lock); + fibril_rwlock_write_unlock(&vol->extents_lock); async_answer_0(icall, EINVAL); return; default: hr_update_ext_state(vol, extent_idx_to_fail, HR_EXT_FAILED); (void)vol->meta_ops->erase_block(ext->svc_id); + block_fini(ext->svc_id); + ext->svc_id = 0; hr_mark_vol_state_dirty(vol); } fibril_rwlock_write_unlock(&vol->states_lock); - fibril_rwlock_read_unlock(&vol->extents_lock); + fibril_rwlock_write_unlock(&vol->extents_lock); vol->hr_ops.vol_state_eval(vol); diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 36b12ae1a9..9ea474938d 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -184,13 +184,13 @@ static void hr_raid1_vol_state_eval_forced(hr_volume_t *vol) size_t rebuild_no = hr_count_extents(vol, HR_EXT_REBUILD); + fibril_rwlock_read_unlock(&vol->states_lock); + fibril_rwlock_read_unlock(&vol->extents_lock); + fibril_mutex_lock(&vol->hotspare_lock); size_t hs_no = vol->hotspare_no; fibril_mutex_unlock(&vol->hotspare_lock); - fibril_rwlock_read_unlock(&vol->states_lock); - fibril_rwlock_read_unlock(&vol->extents_lock); - if (healthy == 0) { if (old_state != HR_VOL_FAULTY) { fibril_rwlock_write_lock(&vol->states_lock); @@ -205,15 +205,12 @@ static void hr_raid1_vol_state_eval_forced(hr_volume_t *vol) fibril_rwlock_write_unlock(&vol->states_lock); } - if (old_state != HR_VOL_REBUILD) { - if (hs_no > 0 || invalid_no > 0 || rebuild_no > 0) { - fid_t fib = fibril_create(hr_raid1_rebuild, - vol); - if (fib == 0) - return; - fibril_start(fib); - fibril_detach(fib); - } + if (hs_no > 0 || invalid_no > 0 || rebuild_no > 0) { + fid_t fib = fibril_create(hr_raid1_rebuild, vol); + if (fib == 0) + return; + fibril_start(fib); + fibril_detach(fib); } } else { if (old_state != HR_VOL_OPTIMAL) { @@ -540,6 +537,8 @@ static errno_t hr_raid1_rebuild(void *arg) hr_mark_vol_state_dirty(vol); + hr_update_vol_state(vol, HR_VOL_DEGRADED); + fibril_rwlock_write_unlock(&vol->states_lock); end: fibril_rwlock_read_unlock(&vol->extents_lock); diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 38d375ce90..66b9a276d5 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -845,6 +845,8 @@ static errno_t hr_raid5_rebuild(void *arg) hr_mark_vol_state_dirty(vol); + hr_update_vol_state(vol, HR_VOL_DEGRADED); + fibril_rwlock_write_unlock(&vol->states_lock); end: fibril_rwlock_read_unlock(&vol->extents_lock); diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index cfefa1047b..e44f01a66c 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -1109,21 +1109,25 @@ errno_t hr_sync_extents(hr_volume_t *vol) errno_t hr_init_rebuild(hr_volume_t *vol, size_t *rebuild_idx) { + HR_DEBUG("%s()", __func__); + errno_t rc = EOK; size_t bad = vol->extent_no; if (vol->level == HR_LVL_0) return EINVAL; + fibril_rwlock_read_lock(&vol->states_lock); + if (vol->state != HR_VOL_DEGRADED) { + fibril_rwlock_read_unlock(&vol->states_lock); + return EINVAL; + } + fibril_rwlock_read_unlock(&vol->states_lock); + fibril_rwlock_write_lock(&vol->extents_lock); fibril_rwlock_write_lock(&vol->states_lock); fibril_mutex_lock(&vol->hotspare_lock); - if (vol->state != HR_VOL_DEGRADED) { - rc = EINVAL; - goto error; - } - size_t rebuild = vol->extent_no; for (size_t i = 0; i < vol->extent_no; i++) { if (vol->extents[i].state == HR_EXT_REBUILD) { From 974f9ba1629496b4be4161b31295cebd582832b1 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 4 Jul 2025 21:42:41 +0200 Subject: [PATCH 308/324] hr: different RAID 1 read strategies First - take first usable extent. Closest - take extent with last seek position. Round-robin - always switch extents. Split - split I/O to multiple extents. --- uspace/srv/bd/hr/io.c | 5 + uspace/srv/bd/hr/raid1.c | 241 ++++++++++++++++++++++++++++++++++----- uspace/srv/bd/hr/util.c | 3 + uspace/srv/bd/hr/var.h | 18 +++ 4 files changed, 237 insertions(+), 30 deletions(-) diff --git a/uspace/srv/bd/hr/io.c b/uspace/srv/bd/hr/io.c index 220d0edc63..fec29fda29 100644 --- a/uspace/srv/bd/hr/io.c +++ b/uspace/srv/bd/hr/io.c @@ -109,6 +109,11 @@ errno_t hr_io_worker(void *arg) 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); diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 9ea474938d..2bead8f811 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -56,7 +56,7 @@ #include "var.h" static void hr_raid1_vol_state_eval_forced(hr_volume_t *); -static size_t hr_raid1_count_good_extents(hr_volume_t *, uint64_t, size_t, +static size_t hr_raid1_count_good_w_extents(hr_volume_t *, uint64_t, size_t, uint64_t); static errno_t hr_raid1_bd_op(hr_bd_op_type_t, hr_volume_t *, aoff64_t, size_t, void *, const void *, size_t); @@ -285,7 +285,7 @@ static errno_t hr_raid1_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb) return EOK; } -static size_t hr_raid1_count_good_extents(hr_volume_t *vol, uint64_t ba, +static size_t hr_raid1_count_good_w_extents(hr_volume_t *vol, uint64_t ba, size_t cnt, uint64_t rebuild_blk) { assert(fibril_rwlock_is_locked(&vol->extents_lock)); @@ -303,6 +303,210 @@ static size_t hr_raid1_count_good_extents(hr_volume_t *vol, uint64_t ba, return count; } +#ifdef HR_RAID1_READ_STRATEGY_SPLIT +static size_t hr_raid1_count_good_r_extents(hr_volume_t *vol, uint64_t ba, + size_t cnt, uint64_t rebuild_blk) +{ + assert(fibril_rwlock_is_locked(&vol->extents_lock)); + assert(fibril_rwlock_is_locked(&vol->states_lock)); + + size_t count = 0; + for (size_t i = 0; i < vol->extent_no; i++) { + if (vol->extents[i].state == HR_EXT_ONLINE || + (vol->extents[i].state == HR_EXT_REBUILD && + rebuild_blk > ba + cnt - 1)) { + count++; + } + } + + return count; +} +#endif + +#ifdef HR_RAID1_READ_STRATEGY_CLOSEST +static size_t get_ext(hr_volume_t *vol, uint64_t ba, size_t cnt, + uint64_t rebuild_blk) +{ + uint64_t closest_e; + uint64_t pos; + uint64_t mdiff = UINT64_MAX; + hr_ext_state_t state = vol->extents[0].state; + if (state != HR_EXT_ONLINE && + (state != HR_EXT_REBUILD || ba + cnt - 1 >= rebuild_blk)) { + closest_e = 1; + } else { + closest_e = 0; + pos = atomic_load_explicit(&vol->last_ext_pos_arr[0], + memory_order_relaxed); + mdiff = (pos > ba) ? pos - ba : ba - pos; + } + + for (size_t e = 1; e < vol->extent_no; e++) { + state = vol->extents[e].state; + if (state != HR_EXT_ONLINE && + (state != HR_EXT_REBUILD || ba + cnt - 1 >= rebuild_blk)) { + continue; + } + + pos = atomic_load_explicit(&vol->last_ext_pos_arr[e], + memory_order_relaxed); + uint64_t diff = (pos > ba) ? pos - ba : ba - pos; + if (diff < mdiff) { + mdiff = diff; + closest_e = e; + } + } + + return closest_e; +} + +#elif defined(HR_RAID1_READ_STRATEGY_ROUND_ROBIN) + +static size_t get_ext(hr_volume_t *vol, uint64_t ba, size_t cnt, + uint64_t rebuild_blk) +{ + size_t last_e; + size_t fail = 0; + + while (true) { + last_e = atomic_fetch_add_explicit(&vol->last_ext_used, 1, + memory_order_relaxed); + last_e %= vol->extent_no; + + hr_ext_state_t state = vol->extents[last_e].state; + if (state != HR_EXT_ONLINE && + (state != HR_EXT_REBUILD || ba + cnt - 1 >= rebuild_blk)) { + if (++fail >= vol->extent_no) + return vol->extent_no; + continue; + } + + break; + } + + return last_e; +} + +#elif defined(HR_RAID1_READ_STRATEGY_FIRST) + +static size_t get_ext(hr_volume_t *vol, uint64_t ba, size_t cnt, + uint64_t rebuild_blk) +{ + for (size_t e = 0; e < vol->extent_no; e++) { + hr_ext_state_t state = vol->extents[e].state; + if (state != HR_EXT_ONLINE && + (state != HR_EXT_REBUILD || ba + cnt - 1 >= rebuild_blk)) { + continue; + } + + return e; + } + return vol->extent_no; +} + +#else + +#if !defined(HR_RAID1_READ_STRATEGY_SPLIT) || \ + !defined(HR_RAID1_READ_STRATEGY_SPLIT_THRESHOLD) +#error "Some RAID 1 read strategy must be used" +#endif + +#endif + +static size_t hr_raid1_read(hr_volume_t *vol, uint64_t ba, size_t cnt, + void *data_read) +{ + uint64_t rebuild_blk; + size_t successful = 0; + +#if !defined(HR_RAID1_READ_STRATEGY_SPLIT) + errno_t rc; + + rebuild_blk = atomic_load_explicit(&vol->rebuild_blk, + memory_order_relaxed); + size_t fail = 0; + while (fail < vol->extent_no) { + fibril_rwlock_read_lock(&vol->states_lock); + size_t best_e = get_ext(vol, ba, cnt, + rebuild_blk); + fibril_rwlock_read_unlock(&vol->states_lock); + if (best_e >= vol->extent_no) + break; + rc = hr_read_direct(vol->extents[best_e].svc_id, ba, + cnt, data_read); + if (rc != EOK) { + hr_raid1_ext_state_cb(vol, best_e, rc); + fail++; + } else { + successful++; + break; + } + } + +#else + +retry_split: + size_t good; + rebuild_blk = atomic_load_explicit(&vol->rebuild_blk, + memory_order_relaxed); + + fibril_rwlock_read_lock(&vol->states_lock); + good = hr_raid1_count_good_r_extents(vol, ba, cnt, + rebuild_blk); + fibril_rwlock_read_unlock(&vol->states_lock); + + size_t cnt_per_ext = (cnt + good - 1) / good; + if (cnt_per_ext * vol->bsize < HR_RAID1_READ_STRATEGY_SPLIT_THRESHOLD) + cnt_per_ext = cnt; + + hr_fgroup_t *group = hr_fgroup_create(vol->fge, good); + + fibril_rwlock_read_lock(&vol->states_lock); + size_t left = cnt; + size_t e = 0; + uint8_t *data = data_read; + size_t submitted = 0; + while (left > 0) { + if (e >= vol->extent_no) { + fibril_rwlock_read_unlock(&vol->states_lock); + if (submitted) + (void)hr_fgroup_wait(group, NULL, NULL); + goto retry_split; + } + + hr_ext_state_t state = vol->extents[e].state; + if (state != HR_EXT_ONLINE && + (state != HR_EXT_REBUILD || + ba + cnt - 1 >= rebuild_blk)) { + e++; + continue; + } + + hr_io_t *io = hr_fgroup_alloc(group); + io->extent = e; + io->data_read = data; + io->ba = ba + (cnt - left); + size_t cnt_to_dispatch = min(left, cnt_per_ext); + io->cnt = cnt_to_dispatch; + io->type = HR_BD_READ; + io->vol = vol; + + hr_fgroup_submit(group, hr_io_worker, io); + submitted++; + + data += cnt_to_dispatch * vol->bsize; + left -= cnt_to_dispatch; + e++; + } + + fibril_rwlock_read_unlock(&vol->states_lock); + + (void)hr_fgroup_wait(group, &successful, NULL); +#endif + + return successful; +} + static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, hr_volume_t *vol, aoff64_t ba, size_t cnt, void *data_read, const void *data_write, size_t size) @@ -311,7 +515,6 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, hr_volume_t *vol, hr_range_lock_t *rl = NULL; errno_t rc; - size_t i; uint64_t rebuild_blk; if (size < cnt * vol->bsize) @@ -344,32 +547,11 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, hr_volume_t *vol, */ fibril_rwlock_read_lock(&vol->extents_lock); - size_t successful = 0; + size_t good; + size_t successful; switch (type) { case HR_BD_READ: - rebuild_blk = atomic_load_explicit(&vol->rebuild_blk, - memory_order_relaxed); - - for (i = 0; i < vol->extent_no; i++) { - fibril_rwlock_read_lock(&vol->states_lock); - hr_ext_state_t state = vol->extents[i].state; - fibril_rwlock_read_unlock(&vol->states_lock); - - if (state != HR_EXT_ONLINE && - (state != HR_EXT_REBUILD || - ba + cnt - 1 >= rebuild_blk)) { - continue; - } - - rc = hr_read_direct(vol->extents[i].svc_id, ba, cnt, - data_read); - if (rc != EOK) { - hr_raid1_ext_state_cb(vol, i, rc); - } else { - successful++; - break; - } - } + successful = hr_raid1_read(vol, ba, cnt, data_read); break; case HR_BD_WRITE: rl = hr_range_lock_acquire(vol, ba, cnt); @@ -379,12 +561,12 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, hr_volume_t *vol, rebuild_blk = atomic_load_explicit(&vol->rebuild_blk, memory_order_relaxed); - size_t good = hr_raid1_count_good_extents(vol, ba, cnt, + good = hr_raid1_count_good_w_extents(vol, ba, cnt, rebuild_blk); hr_fgroup_t *group = hr_fgroup_create(vol->fge, good); - for (i = 0; i < vol->extent_no; i++) { + for (size_t i = 0; i < vol->extent_no; i++) { if (vol->extents[i].state != HR_EXT_ONLINE && (vol->extents[i].state != HR_EXT_REBUILD || ba > rebuild_blk)) { @@ -401,7 +583,6 @@ static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, hr_volume_t *vol, hr_io_t *io = hr_fgroup_alloc(group); io->extent = i; io->data_write = data_write; - io->data_read = data_read; io->ba = ba; io->cnt = cnt; io->type = type; diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index e44f01a66c..38b099f0b9 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -168,6 +168,9 @@ errno_t hr_create_vol_struct(hr_volume_t **rvol, hr_level_t level, atomic_init(&vol->state_dirty, false); atomic_init(&vol->first_write, false); + for (size_t i = 0; i < HR_MAX_EXTENTS; i++) + atomic_init(&vol->last_ext_pos_arr[i], 0); + atomic_init(&vol->last_ext_used, 0); atomic_init(&vol->rebuild_blk, 0); atomic_init(&vol->open_cnt, 0); diff --git a/uspace/srv/bd/hr/var.h b/uspace/srv/bd/hr/var.h index c8ad629feb..48f4bec5aa 100644 --- a/uspace/srv/bd/hr/var.h +++ b/uspace/srv/bd/hr/var.h @@ -49,6 +49,21 @@ #define NAME "hr" #define HR_STRIP_SIZE DATA_XFER_LIMIT +#define HR_RAID1_READ_STRATEGY_SPLIT +#define HR_RAID1_READ_STRATEGY_SPLIT_THRESHOLD (1024 * 1) + +/* #define HR_RAID1_READ_STRATEGY_CLOSEST */ +/* #define HR_RAID1_READ_STRATEGY_ROUND_ROBIN */ +/* #define HR_RAID1_READ_STRATEGY_FIRST */ + +#if !defined(HR_RAID1_READ_STRATEGY_ROUND_ROBIN) && \ + !defined(HR_RAID1_READ_STRATEGY_CLOSEST) && \ + !defined(HR_RAID1_READ_STRATEGY_FIRST) && \ + (!defined(HR_RAID1_READ_STRATEGY_SPLIT) && \ + !defined(HR_RAID1_READ_STRATEGY_SPLIT_THRESHOLD)) +#error "Some RAID 1 read strategy must be used" +#endif + /* * During a rebuild operation, we save the rebuild * position this each many bytes. Currently each @@ -113,6 +128,9 @@ typedef struct hr_volume { */ _Atomic bool first_write; + _Atomic uint64_t last_ext_pos_arr[HR_MAX_EXTENTS]; + _Atomic uint64_t last_ext_used; + _Atomic uint64_t rebuild_blk; /* rebuild position */ _Atomic int open_cnt; /* open/close() counter */ hr_vol_state_t state; /* volume state */ From c76bf3364a0f7f1b69128033743cd8f4628c2985 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 6 Jul 2025 01:02:28 +0200 Subject: [PATCH 309/324] hr: raid1.c: update rebuild extent's last seek pos --- uspace/srv/bd/hr/raid1.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 2bead8f811..fb3046c68a 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -304,6 +304,7 @@ static size_t hr_raid1_count_good_w_extents(hr_volume_t *vol, uint64_t ba, } #ifdef HR_RAID1_READ_STRATEGY_SPLIT + static size_t hr_raid1_count_good_r_extents(hr_volume_t *vol, uint64_t ba, size_t cnt, uint64_t rebuild_blk) { @@ -321,9 +322,11 @@ static size_t hr_raid1_count_good_r_extents(hr_volume_t *vol, uint64_t ba, return count; } -#endif + +#endif /* HR_RAID1_READ_STRATEGY_SPLIT */ #ifdef HR_RAID1_READ_STRATEGY_CLOSEST + static size_t get_ext(hr_volume_t *vol, uint64_t ba, size_t cnt, uint64_t rebuild_blk) { @@ -685,6 +688,8 @@ static errno_t hr_raid1_rebuild(void *arg) hr_range_lock_release(rl); goto end; } + atomic_store_explicit(&vol->last_ext_pos_arr[rebuild_idx], + ba + cnt - 1, memory_order_relaxed); percent = ((ba + cnt) * 100) / vol->data_blkno; if (percent != old_percent) { From 3b14bda1cc9b22c1b66da22f6bcb2b408347d2a6 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 6 Jul 2025 11:21:52 +0200 Subject: [PATCH 310/324] hr: raid1.c: retry split in case of failure --- uspace/srv/bd/hr/raid1.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index fb3046c68a..ac86880bd1 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -505,6 +505,9 @@ static size_t hr_raid1_read(hr_volume_t *vol, uint64_t ba, size_t cnt, fibril_rwlock_read_unlock(&vol->states_lock); (void)hr_fgroup_wait(group, &successful, NULL); + if (successful < submitted) + goto retry_split; + #endif return successful; From 1162b6c8ace3bf1d17e6ff1a6f574ecb997ee817 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 7 Jul 2025 02:54:46 +0200 Subject: [PATCH 311/324] hr: raid1.c: split read: abort on 0 good extents --- uspace/srv/bd/hr/raid1.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index ac86880bd1..99e7eb2efa 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -458,6 +458,9 @@ static size_t hr_raid1_read(hr_volume_t *vol, uint64_t ba, size_t cnt, rebuild_blk); fibril_rwlock_read_unlock(&vol->states_lock); + if (good == 0) + return 0; + size_t cnt_per_ext = (cnt + good - 1) / good; if (cnt_per_ext * vol->bsize < HR_RAID1_READ_STRATEGY_SPLIT_THRESHOLD) cnt_per_ext = cnt; From 15e51b05f97c4d8273ff4f17df1733fd4adffe26 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 7 Jul 2025 13:04:41 +0200 Subject: [PATCH 312/324] hr: check extent number --- uspace/srv/bd/hr/hr.c | 8 ++++++++ uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c | 2 +- uspace/srv/bd/hr/metadata/native.c | 6 ++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 14871d101c..67688bbac9 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -112,6 +112,14 @@ static void hr_create_srv(ipc_call_t *icall) return; } + if (cfg->dev_no > HR_MAX_EXTENTS) { + HR_ERROR("provided %u devices (max = %u)", + (unsigned)cfg->dev_no, HR_MAX_EXTENTS); + free(cfg); + async_answer_0(icall, ELIMIT); + return; + } + /* * If there was a missing device provided * for creation of a new volume, abort diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c index 1f0db8edc4..9e4654a072 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c @@ -167,7 +167,7 @@ static errno_t meta_gstripe_init_meta2vol(const list_t *list, hr_volume_t *vol) vol->data_offset = 0; - if (main_meta->md_all > HR_MAX_EXTENTS) { + if (vol->extent_no > HR_MAX_EXTENTS) { HR_DEBUG("Assembled volume has %u extents (max = %u)", (unsigned)main_meta->md_all, HR_MAX_EXTENTS); rc = EINVAL; diff --git a/uspace/srv/bd/hr/metadata/native.c b/uspace/srv/bd/hr/metadata/native.c index fb764fb2dc..5f27dd5dd8 100644 --- a/uspace/srv/bd/hr/metadata/native.c +++ b/uspace/srv/bd/hr/metadata/native.c @@ -188,6 +188,12 @@ static errno_t meta_native_init_meta2vol(const list_t *list, hr_volume_t *vol) /* already set */ /* memcpy(vol->devname, main_meta->devname, HR_DEVNAME_LEN); */ + if (vol->extent_no > HR_MAX_EXTENTS) { + HR_DEBUG("Assembled volume has %u extents (max = %u)", + (unsigned)vol->extent_no, HR_MAX_EXTENTS); + return EINVAL; + } + vol->in_mem_md = calloc(1, sizeof(hr_metadata_t)); if (vol->in_mem_md == NULL) return ENOMEM; From 9323bb8fc1f5855a35878257d36061f27d54fc2e Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 7 Jul 2025 18:04:02 +0200 Subject: [PATCH 313/324] hr: raid5.c: make the critical section smaller --- uspace/srv/bd/hr/raid5.c | 60 ++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 66b9a276d5..360854f1c0 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -97,10 +97,6 @@ errno_t hr_raid5_create(hr_volume_t *new_volume) return EINVAL; } - bd_srvs_init(&new_volume->hr_bds); - new_volume->hr_bds.ops = &hr_raid5_bd_ops; - new_volume->hr_bds.sarg = new_volume; - hr_raid5_vol_state_eval_forced(new_volume); fibril_rwlock_read_lock(&new_volume->states_lock); @@ -112,6 +108,10 @@ errno_t hr_raid5_create(hr_volume_t *new_volume) return EINVAL; } + bd_srvs_init(&new_volume->hr_bds); + new_volume->hr_bds.ops = &hr_raid5_bd_ops; + new_volume->hr_bds.sarg = new_volume; + return EOK; } @@ -240,19 +240,6 @@ static errno_t hr_raid5_bd_read_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt, hr_stripe_t *stripes = hr_create_stripes(vol, vol->strip_size, stripes_cnt, false); - hr_range_lock_t **rlps = hr_malloc_waitok(stripes_cnt * sizeof(*rlps)); - - /* - * extent order has to be locked for the whole IO duration, - * so that workers have consistent targets - */ - fibril_rwlock_read_lock(&vol->extents_lock); - - for (uint64_t s = start_stripe; s <= end_stripe; s++) { - uint64_t relative = s - start_stripe; - rlps[relative] = hr_range_lock_acquire(vol, s, 1); - } - uint64_t phys_block, len; size_t left; @@ -300,6 +287,19 @@ static errno_t hr_raid5_bd_read_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt, strip_no++; } + hr_range_lock_t **rlps = hr_malloc_waitok(stripes_cnt * sizeof(*rlps)); + + /* + * extent order has to be locked for the whole IO duration, + * so that workers have consistent targets + */ + fibril_rwlock_read_lock(&vol->extents_lock); + + for (uint64_t s = start_stripe; s <= end_stripe; s++) { + uint64_t relative = s - start_stripe; + rlps[relative] = hr_range_lock_acquire(vol, s, 1); + } + retry: size_t bad_extent = vol->extent_no; @@ -451,19 +451,6 @@ static errno_t hr_raid5_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, stripes[relative_stripe].subtract = true; } - hr_range_lock_t **rlps = hr_malloc_waitok(stripes_cnt * sizeof(*rlps)); - - /* - * extent order has to be locked for the whole IO duration, - * so that workers have consistent targets - */ - fibril_rwlock_read_lock(&vol->extents_lock); - - for (uint64_t s = start_stripe; s <= end_stripe; s++) { - uint64_t relative = s - start_stripe; - rlps[relative] = hr_range_lock_acquire(vol, s, 1); - } - uint64_t phys_block, len; size_t left; @@ -509,6 +496,19 @@ static errno_t hr_raid5_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, strip_no++; } + hr_range_lock_t **rlps = hr_malloc_waitok(stripes_cnt * sizeof(*rlps)); + + /* + * extent order has to be locked for the whole IO duration, + * so that workers have consistent targets + */ + fibril_rwlock_read_lock(&vol->extents_lock); + + for (uint64_t s = start_stripe; s <= end_stripe; s++) { + uint64_t relative = s - start_stripe; + rlps[relative] = hr_range_lock_acquire(vol, s, 1); + } + retry: size_t bad_extent = vol->extent_no; From f7169a64d9148e52fd75afe3a6c6442db340d475 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 8 Jul 2025 02:29:28 +0200 Subject: [PATCH 314/324] hr: raid5.c, parity_stripe.c: rename exec fcns --- uspace/srv/bd/hr/parity_stripe.c | 49 +++++++++++++++++--------------- uspace/srv/bd/hr/parity_stripe.h | 4 +-- uspace/srv/bd/hr/raid5.c | 8 +++--- 3 files changed, 32 insertions(+), 29 deletions(-) diff --git a/uspace/srv/bd/hr/parity_stripe.c b/uspace/srv/bd/hr/parity_stripe.c index 58340520bf..fe9a6c96ab 100644 --- a/uspace/srv/bd/hr/parity_stripe.c +++ b/uspace/srv/bd/hr/parity_stripe.c @@ -42,13 +42,13 @@ #include "util.h" #include "var.h" -static void execute_stripe_degraded_mixed(hr_stripe_t *, size_t); -static void execute_stripe_degraded(hr_stripe_t *, size_t); -static void execute_stripe_optimal_reconstruct(hr_stripe_t *); -static void execute_stripe_optimal_subtract(hr_stripe_t *); -static void execute_write_stripe(hr_stripe_t *, size_t); -static void execute_read_stripe(hr_stripe_t *, size_t); -static void execute_stripe_degraded_good(hr_stripe_t *, size_t); +static void hr_execute_write_stripe_degraded_mixed(hr_stripe_t *, size_t); +static void hr_execute_write_stripe_degraded(hr_stripe_t *, size_t); +static void hr_execute_write_stripe_optimal_reconstruct(hr_stripe_t *); +static void hr_execute_write_stripe_optimal_subtract(hr_stripe_t *); +static void hr_execute_write_stripe(hr_stripe_t *, size_t); +static void hr_execute_read_stripe(hr_stripe_t *, size_t); +static void hr_execute_write_stripe_degraded_good(hr_stripe_t *, size_t); static bool hr_stripe_range_non_extension(const range_t *, const range_t *, range_t *); static size_t hr_stripe_merge_extent_spans(hr_stripe_t *, size_t, range_t [2]); @@ -129,15 +129,15 @@ void hr_stripe_parity_abort(hr_stripe_t *stripe) fibril_mutex_unlock(&stripe->parity_lock); } -void execute_stripe(hr_stripe_t *stripe, size_t bad_extent) +void hr_execute_stripe(hr_stripe_t *stripe, size_t bad_extent) { if (stripe->write) - execute_write_stripe(stripe, bad_extent); + hr_execute_write_stripe(stripe, bad_extent); else - execute_read_stripe(stripe, bad_extent); + hr_execute_read_stripe(stripe, bad_extent); } -void wait_for_stripe(hr_stripe_t *stripe) +void hr_wait_for_stripe(hr_stripe_t *stripe) { stripe->rc = hr_fgroup_wait(stripe->worker_group, NULL, NULL); if (stripe->rc == EAGAIN) @@ -146,7 +146,8 @@ void wait_for_stripe(hr_stripe_t *stripe) stripe->done = true; } -static void execute_stripe_degraded_good(hr_stripe_t *stripe, size_t bad_extent) +static void hr_execute_write_stripe_degraded_good(hr_stripe_t *stripe, + size_t bad_extent) { hr_volume_t *vol = stripe->vol; @@ -211,7 +212,8 @@ static void execute_stripe_degraded_good(hr_stripe_t *stripe, size_t bad_extent) } } -static void execute_stripe_degraded_mixed(hr_stripe_t *stripe, size_t bad_extent) +static void hr_execute_write_stripe_degraded_mixed(hr_stripe_t *stripe, + size_t bad_extent) { hr_volume_t *vol = stripe->vol; @@ -382,7 +384,8 @@ static void execute_stripe_degraded_mixed(hr_stripe_t *stripe, size_t bad_extent fibril_condvar_broadcast(&stripe->ps_added_cv); } -static void execute_stripe_degraded(hr_stripe_t *stripe, size_t bad_extent) +static void hr_execute_write_stripe_degraded(hr_stripe_t *stripe, + size_t bad_extent) { hr_volume_t *vol = stripe->vol; @@ -419,12 +422,12 @@ static void execute_stripe_degraded(hr_stripe_t *stripe, size_t bad_extent) vol->extent_no, stripe->total_height); if (stripe->extent_span[bad_extent].cnt > 0) - execute_stripe_degraded_mixed(stripe, bad_extent); + hr_execute_write_stripe_degraded_mixed(stripe, bad_extent); else - execute_stripe_degraded_good(stripe, bad_extent); + hr_execute_write_stripe_degraded_good(stripe, bad_extent); } -static void execute_stripe_optimal_reconstruct(hr_stripe_t *stripe) +static void hr_execute_write_stripe_optimal_reconstruct(hr_stripe_t *stripe) { hr_volume_t *vol = stripe->vol; @@ -542,7 +545,7 @@ static void execute_stripe_optimal_reconstruct(hr_stripe_t *stripe) } } -static void execute_stripe_optimal_subtract(hr_stripe_t *stripe) +static void hr_execute_write_stripe_optimal_subtract(hr_stripe_t *stripe) { hr_volume_t *vol = stripe->vol; @@ -615,22 +618,22 @@ static void execute_stripe_optimal_subtract(hr_stripe_t *stripe) } -static void execute_write_stripe(hr_stripe_t *stripe, size_t bad_extent) +static void hr_execute_write_stripe(hr_stripe_t *stripe, size_t bad_extent) { hr_volume_t *vol = stripe->vol; if (bad_extent < vol->extent_no) { - execute_stripe_degraded(stripe, bad_extent); + hr_execute_write_stripe_degraded(stripe, bad_extent); return; } if (stripe->subtract) - execute_stripe_optimal_subtract(stripe); + hr_execute_write_stripe_optimal_subtract(stripe); else - execute_stripe_optimal_reconstruct(stripe); + hr_execute_write_stripe_optimal_reconstruct(stripe); } -static void execute_read_stripe(hr_stripe_t *stripe, size_t bad_extent) +static void hr_execute_read_stripe(hr_stripe_t *stripe, size_t bad_extent) { hr_volume_t *vol = stripe->vol; diff --git a/uspace/srv/bd/hr/parity_stripe.h b/uspace/srv/bd/hr/parity_stripe.h index 655b08d5bc..6232379a8c 100644 --- a/uspace/srv/bd/hr/parity_stripe.h +++ b/uspace/srv/bd/hr/parity_stripe.h @@ -111,8 +111,8 @@ extern void hr_stripe_commit_parity(hr_stripe_t *, uint64_t, const void *, uint64_t); extern void hr_stripe_wait_for_parity_commits(hr_stripe_t *); extern void hr_stripe_parity_abort(hr_stripe_t *); -extern void execute_stripe(hr_stripe_t *, size_t); -extern void wait_for_stripe(hr_stripe_t *); +extern void hr_execute_stripe(hr_stripe_t *, size_t); +extern void hr_wait_for_stripe(hr_stripe_t *); #endif diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 360854f1c0..c4ad2acf54 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -322,13 +322,13 @@ static errno_t hr_raid5_bd_read_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt, for (size_t s = 0; s < stripes_cnt; s++) { if (stripes[s].done) continue; - execute_stripe(&stripes[s], bad_extent); + hr_execute_stripe(&stripes[s], bad_extent); } for (size_t s = 0; s < stripes_cnt; s++) { if (stripes[s].done) continue; - wait_for_stripe(&stripes[s]); + hr_wait_for_stripe(&stripes[s]); } hr_raid5_vol_state_eval(vol); @@ -531,13 +531,13 @@ static errno_t hr_raid5_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, for (size_t s = 0; s < stripes_cnt; s++) { if (stripes[s].done) continue; - execute_stripe(&stripes[s], bad_extent); + hr_execute_stripe(&stripes[s], bad_extent); } for (size_t s = 0; s < stripes_cnt; s++) { if (stripes[s].done) continue; - wait_for_stripe(&stripes[s]); + hr_wait_for_stripe(&stripes[s]); } hr_raid5_vol_state_eval(vol); From ba65caf51cf72a8bc0de637d11a9243f32e4180d Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 8 Jul 2025 16:43:40 +0200 Subject: [PATCH 315/324] hr: hr.c: potentially answer EBUSY on HR_STOP_ALL --- uspace/srv/bd/hr/hr.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 67688bbac9..3ab5ea730a 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -332,8 +332,11 @@ static void hr_stop_all_srv(ipc_call_t *icall) if (rc != EOK) goto fail; - for (i = 0; i < vol_cnt; i++) - (void)hr_remove_volume(vol_svcs[i]); + for (i = 0; i < vol_cnt; i++) { + errno_t rc2 = hr_remove_volume(vol_svcs[i]); + if (rc2 == EBUSY) + rc = EBUSY; + } fail: if (vol_svcs != NULL) From c5c367a2c27ec87a6bf1ec1bed04bf8247853b8e Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 8 Jul 2025 22:55:31 +0200 Subject: [PATCH 316/324] hr: use optimal subtract-write in degraded state --- uspace/srv/bd/hr/parity_stripe.c | 83 +++----------------------------- 1 file changed, 8 insertions(+), 75 deletions(-) diff --git a/uspace/srv/bd/hr/parity_stripe.c b/uspace/srv/bd/hr/parity_stripe.c index fe9a6c96ab..17dc79d03c 100644 --- a/uspace/srv/bd/hr/parity_stripe.c +++ b/uspace/srv/bd/hr/parity_stripe.c @@ -45,10 +45,9 @@ static void hr_execute_write_stripe_degraded_mixed(hr_stripe_t *, size_t); static void hr_execute_write_stripe_degraded(hr_stripe_t *, size_t); static void hr_execute_write_stripe_optimal_reconstruct(hr_stripe_t *); -static void hr_execute_write_stripe_optimal_subtract(hr_stripe_t *); +static void hr_execute_write_stripe_subtract(hr_stripe_t *, size_t); static void hr_execute_write_stripe(hr_stripe_t *, size_t); static void hr_execute_read_stripe(hr_stripe_t *, size_t); -static void hr_execute_write_stripe_degraded_good(hr_stripe_t *, size_t); static bool hr_stripe_range_non_extension(const range_t *, const range_t *, range_t *); static size_t hr_stripe_merge_extent_spans(hr_stripe_t *, size_t, range_t [2]); @@ -146,77 +145,14 @@ void hr_wait_for_stripe(hr_stripe_t *stripe) stripe->done = true; } -static void hr_execute_write_stripe_degraded_good(hr_stripe_t *stripe, - size_t bad_extent) -{ - hr_volume_t *vol = stripe->vol; - - stripe->ps_to_be_added = stripe->strips_touched; /* writers */ - stripe->ps_to_be_added += stripe->range_count; /* parity readers */ - stripe->p_count_final = true; - - size_t worker_cnt = stripe->strips_touched + stripe->range_count * 2; - stripe->worker_group = hr_fgroup_create(vol->fge, worker_cnt); - - for (size_t e = 0; e < vol->extent_no; e++) { - if (e == bad_extent || e == stripe->p_extent) - continue; - if (stripe->extent_span[e].cnt == 0) - continue; - - hr_io_raid5_t *io = hr_fgroup_alloc(stripe->worker_group); - io->extent = e; - io->data_write = stripe->extent_span[e].data_write; - io->ba = stripe->extent_span[e].range.start; - io->cnt = stripe->extent_span[e].cnt; - io->strip_off = stripe->extent_span[e].strip_off * vol->bsize; - io->vol = vol; - io->stripe = stripe; - - hr_fgroup_submit(stripe->worker_group, - hr_io_raid5_subtract_writer, io); - } - - for (size_t r = 0; r < stripe->range_count; r++) { - hr_io_raid5_t *p_reader = hr_fgroup_alloc(stripe->worker_group); - p_reader->extent = stripe->p_extent; - p_reader->ba = stripe->total_height[r].start; - p_reader->cnt = stripe->total_height[r].end - - stripe->total_height[r].start + 1; - p_reader->vol = vol; - p_reader->stripe = stripe; - - p_reader->strip_off = p_reader->ba; - hr_sub_data_offset(vol, &p_reader->strip_off); - p_reader->strip_off %= vol->strip_size / vol->bsize; - p_reader->strip_off *= vol->bsize; - - hr_fgroup_submit(stripe->worker_group, - hr_io_raid5_reconstruct_reader, p_reader); - - hr_io_raid5_t *p_writer = hr_fgroup_alloc(stripe->worker_group); - p_writer->extent = stripe->p_extent; - p_writer->ba = stripe->total_height[r].start; - p_writer->cnt = stripe->total_height[r].end - - stripe->total_height[r].start + 1; - p_writer->vol = vol; - p_writer->stripe = stripe; - - p_writer->strip_off = p_writer->ba; - hr_sub_data_offset(vol, &p_writer->strip_off); - p_writer->strip_off %= vol->strip_size / vol->bsize; - p_writer->strip_off *= vol->bsize; - - hr_fgroup_submit(stripe->worker_group, - hr_io_raid5_parity_writer, p_writer); - } -} - static void hr_execute_write_stripe_degraded_mixed(hr_stripe_t *stripe, size_t bad_extent) { hr_volume_t *vol = stripe->vol; + stripe->range_count = hr_stripe_merge_extent_spans(stripe, + vol->extent_no, stripe->total_height); + size_t worker_cnt = (vol->extent_no - 2) * 3 + 3; /* upper bound */ stripe->worker_group = hr_fgroup_create(vol->fge, worker_cnt); @@ -418,13 +354,10 @@ static void hr_execute_write_stripe_degraded(hr_stripe_t *stripe, return; } - stripe->range_count = hr_stripe_merge_extent_spans(stripe, - vol->extent_no, stripe->total_height); - if (stripe->extent_span[bad_extent].cnt > 0) hr_execute_write_stripe_degraded_mixed(stripe, bad_extent); else - hr_execute_write_stripe_degraded_good(stripe, bad_extent); + hr_execute_write_stripe_subtract(stripe, bad_extent); } static void hr_execute_write_stripe_optimal_reconstruct(hr_stripe_t *stripe) @@ -545,7 +478,7 @@ static void hr_execute_write_stripe_optimal_reconstruct(hr_stripe_t *stripe) } } -static void hr_execute_write_stripe_optimal_subtract(hr_stripe_t *stripe) +static void hr_execute_write_stripe_subtract(hr_stripe_t *stripe, size_t bad) { hr_volume_t *vol = stripe->vol; @@ -563,7 +496,7 @@ static void hr_execute_write_stripe_optimal_subtract(hr_stripe_t *stripe) stripe->worker_group = hr_fgroup_create(vol->fge, worker_cnt); for (size_t e = 0; e < vol->extent_no; e++) { - if (e == stripe->p_extent) + if (e == bad || e == stripe->p_extent) continue; if (stripe->extent_span[e].cnt == 0) @@ -628,7 +561,7 @@ static void hr_execute_write_stripe(hr_stripe_t *stripe, size_t bad_extent) } if (stripe->subtract) - hr_execute_write_stripe_optimal_subtract(stripe); + hr_execute_write_stripe_subtract(stripe, vol->extent_no); else hr_execute_write_stripe_optimal_reconstruct(stripe); } From 9c3369b91a885914a5d30f5ac4858ccbe735034f Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Wed, 9 Jul 2025 11:04:58 +0200 Subject: [PATCH 317/324] hr: raid5.c: remove unused rebuild bufs --- uspace/srv/bd/hr/raid5.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index c4ad2acf54..1b8b687de3 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -706,7 +706,6 @@ static errno_t hr_raid5_rebuild(void *arg) hr_volume_t *vol = arg; errno_t rc = EOK; size_t rebuild_idx; - void *buf = NULL, *xorbuf = NULL; if (vol->vflags & HR_VOL_FLAG_READ_ONLY) return ENOTSUP; @@ -720,8 +719,6 @@ static errno_t hr_raid5_rebuild(void *arg) uint64_t max_blks = DATA_XFER_LIMIT / vol->bsize; uint64_t left = vol->data_blkno / (vol->extent_no - 1) - vol->rebuild_blk; - buf = hr_malloc_waitok(max_blks * vol->bsize); - xorbuf = hr_malloc_waitok(max_blks * vol->bsize); uint64_t strip_size = vol->strip_size / vol->bsize; /* in blocks */ @@ -854,8 +851,6 @@ static errno_t hr_raid5_rebuild(void *arg) hr_raid1_vol_state_eval(vol); hr_destroy_stripes(stripe, 1); - free(buf); - free(xorbuf); return rc; } From b127da2f04985d8e204ee04bb0c448fd03c8aed2 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 11 Jul 2025 21:48:47 +0200 Subject: [PATCH 318/324] hr: careful assembly --- .../bd/hr/metadata/foreign/geom/hr_g_mirror.c | 1 - .../bd/hr/metadata/foreign/geom/hr_g_stripe.c | 1 - uspace/srv/bd/hr/metadata/foreign/md/hr_md.c | 1 - .../metadata/foreign/softraid/hr_softraid.c | 1 - uspace/srv/bd/hr/metadata/native.c | 1 - uspace/srv/bd/hr/util.c | 33 +++++++++++++++++-- 6 files changed, 30 insertions(+), 8 deletions(-) diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c index 55dd041838..fb860160f4 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c @@ -188,7 +188,6 @@ static errno_t meta_gmirror_init_meta2vol(const list_t *list, hr_volume_t *vol) memcpy(p, iter_meta, sizeof(*p)); vol->extents[index].svc_id = iter->svc_id; - iter->fini = false; bool invalidate = false; bool rebuild_this_ext = false; diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c index 9e4654a072..857312f511 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c @@ -188,7 +188,6 @@ static errno_t meta_gstripe_init_meta2vol(const list_t *list, hr_volume_t *vol) uint16_t index = iter_meta->md_no; vol->extents[index].svc_id = iter->svc_id; - iter->fini = false; vol->extents[index].state = HR_EXT_ONLINE; } diff --git a/uspace/srv/bd/hr/metadata/foreign/md/hr_md.c b/uspace/srv/bd/hr/metadata/foreign/md/hr_md.c index 24a74c2ae9..45533c26b9 100644 --- a/uspace/srv/bd/hr/metadata/foreign/md/hr_md.c +++ b/uspace/srv/bd/hr/metadata/foreign/md/hr_md.c @@ -205,7 +205,6 @@ static errno_t meta_md_init_meta2vol(const list_t *list, hr_volume_t *vol) memcpy(p, iter_meta, MD_SIZE * 512); vol->extents[index].svc_id = iter->svc_id; - iter->fini = false; bool invalidate = false; bool rebuild_this_ext = false; diff --git a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c index e62c9a8bde..c1cb5415a5 100644 --- a/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c +++ b/uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c @@ -188,7 +188,6 @@ static errno_t meta_softraid_init_meta2vol(const list_t *list, hr_volume_t *vol) uint8_t index = iter_meta->ssdi.ssd_chunk_id; vol->extents[index].svc_id = iter->svc_id; - iter->fini = false; struct sr_meta_chunk *mc = ((struct sr_meta_chunk *)(main_meta + 1)) + index; diff --git a/uspace/srv/bd/hr/metadata/native.c b/uspace/srv/bd/hr/metadata/native.c index 5f27dd5dd8..c2441fa6bc 100644 --- a/uspace/srv/bd/hr/metadata/native.c +++ b/uspace/srv/bd/hr/metadata/native.c @@ -203,7 +203,6 @@ static errno_t meta_native_init_meta2vol(const list_t *list, hr_volume_t *vol) hr_metadata_t *iter_meta = (hr_metadata_t *)iter->md; vol->extents[iter_meta->index].svc_id = iter->svc_id; - iter->fini = false; hr_ext_state_t final_ext_state = HR_EXT_INVALID; if (iter_meta->counter == max_counter_val) { diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 38b099f0b9..89274f68ea 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -620,6 +620,7 @@ static errno_t hr_add_svc_linked_to_list(list_t *list, service_id_t svc_id, to_add->svc_id = svc_id; to_add->inited = inited; + to_add->fini = true; if (md != NULL) { to_add->md = md; @@ -857,6 +858,15 @@ static errno_t hr_util_assemble_from_matching_list(list_t *list, if (rc != EOK) goto error; + for (size_t e = 0; e < vol->extent_no; e++) { + if (vol->extents[e].svc_id == 0) + continue; + list_foreach(*list, link, struct dev_list_member, iter) { + if (iter->svc_id == vol->extents[e].svc_id) + iter->fini = false; + } + } + rc = hr_register_volume(vol); if (rc != EOK) goto error; @@ -869,7 +879,12 @@ static errno_t hr_util_assemble_from_matching_list(list_t *list, return EOK; error: + /* let the caller fini the block svc list */ + for (size_t e = 0; e < vol->extent_no; e++) + vol->extents[e].svc_id = 0; + hr_destroy_vol_struct(vol); + return rc; } @@ -944,13 +959,19 @@ errno_t hr_util_try_assemble(hr_config_t *cfg, size_t *rassembled_cnt) continue; } - if (rc != EOK) + if (rc != EOK) { + block_fini(iter->svc_id); + free_dev_list_member(iter); goto error; + } char *svc_name = NULL; rc = loc_service_get_name(iter->svc_id, &svc_name); - if (rc != EOK) + if (rc != EOK) { + block_fini(iter->svc_id); + free_dev_list_member(iter); goto error; + } HR_DEBUG("found valid metadata on %s (type = %s), matching " "other extents\n", svc_name, hr_get_metadata_type_str(type)); @@ -961,17 +982,23 @@ errno_t hr_util_try_assemble(hr_config_t *cfg, size_t *rassembled_cnt) rc = hr_util_get_matching_md_svcs_list(&matching_svcs_list, &dev_id_list, iter->svc_id, type, metadata_struct_main); - if (rc != EOK) + if (rc != EOK) { + block_fini(iter->svc_id); + free_dev_list_member(iter); goto error; + } /* add current iter to list as well */ rc = hr_add_svc_linked_to_list(&matching_svcs_list, iter->svc_id, true, metadata_struct_main); if (rc != EOK) { + block_fini(iter->svc_id); free_svc_id_list(&matching_svcs_list); goto error; } + free_dev_list_member(iter); + /* remove matching list members from dev_id_list */ list_foreach(matching_svcs_list, link, struct dev_list_member, iter2) { From ca212a519e7b756a1c5a2b63f186eb5ff442e7ac Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Fri, 11 Jul 2025 22:13:38 +0200 Subject: [PATCH 319/324] hr: RAID 0, 5: init strip size to closest (down) pow of 2 --- uspace/srv/bd/hr/raid0.c | 2 +- uspace/srv/bd/hr/raid5.c | 2 +- uspace/srv/bd/hr/util.c | 13 +++++++++++++ uspace/srv/bd/hr/util.h | 1 + 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/uspace/srv/bd/hr/raid0.c b/uspace/srv/bd/hr/raid0.c index 67b77ec96e..225edc3ed4 100644 --- a/uspace/srv/bd/hr/raid0.c +++ b/uspace/srv/bd/hr/raid0.c @@ -122,7 +122,7 @@ errno_t hr_raid0_init(hr_volume_t *vol) /* count md blocks */ vol->data_blkno -= vol->meta_ops->get_size() * vol->extent_no; - vol->strip_size = HR_STRIP_SIZE; + vol->strip_size = hr_closest_pow2(HR_STRIP_SIZE / vol->extent_no); return EOK; } diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 1b8b687de3..36170159a8 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -130,7 +130,7 @@ errno_t hr_raid5_init(hr_volume_t *vol) uint64_t single_sz = vol->truncated_blkno - vol->meta_ops->get_size(); vol->data_blkno = single_sz * (vol->extent_no - 1); - vol->strip_size = HR_STRIP_SIZE; + vol->strip_size = hr_closest_pow2(HR_STRIP_SIZE / (vol->extent_no - 1)); if (vol->level == HR_LVL_4) vol->layout = HR_LAYOUT_RAID4_N; diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 89274f68ea..442bfcfe63 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -1253,5 +1253,18 @@ static errno_t hr_swap_hs(hr_volume_t *vol, size_t bad, size_t hs) return EOK; } +uint32_t hr_closest_pow2(uint32_t n) +{ + if (n == 0) + return 0; + + n |= (n >> 1); + n |= (n >> 2); + n |= (n >> 4); + n |= (n >> 8); + n |= (n >> 16); + return n - (n >> 1); +} + /** @} */ diff --git a/uspace/srv/bd/hr/util.h b/uspace/srv/bd/hr/util.h index 21d00f0de6..45e7ac548e 100644 --- a/uspace/srv/bd/hr/util.h +++ b/uspace/srv/bd/hr/util.h @@ -110,6 +110,7 @@ extern errno_t hr_util_add_hotspare(hr_volume_t *, service_id_t); extern void hr_raid5_xor(void *, const void *, size_t); extern errno_t hr_sync_extents(hr_volume_t *); extern errno_t hr_init_rebuild(hr_volume_t *, size_t *); +extern uint32_t hr_closest_pow2(uint32_t); #endif From a0abd460cb2916c83ae85a2af31698be9d3674c6 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Sun, 13 Jul 2025 12:18:18 +0200 Subject: [PATCH 320/324] hr: increase upper fibril bound of reconstruct write --- uspace/srv/bd/hr/parity_stripe.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/uspace/srv/bd/hr/parity_stripe.c b/uspace/srv/bd/hr/parity_stripe.c index 17dc79d03c..d8f65295ec 100644 --- a/uspace/srv/bd/hr/parity_stripe.c +++ b/uspace/srv/bd/hr/parity_stripe.c @@ -383,7 +383,8 @@ static void hr_execute_write_stripe_optimal_reconstruct(hr_stripe_t *stripe) worker_cnt = stripe->strips_touched; /* writers */ /* readers (upper bound) */ - worker_cnt += (vol->extent_no - 1) - stripe->strips_touched; + worker_cnt += ((vol->extent_no - 1) - stripe->strips_touched) * + stripe->range_count; worker_cnt += stripe->partial_strips_touched; worker_cnt += stripe->range_count; /* parity writer(s) */ From 09e01d230388cfdb9e45a9d68978791fd4b356bb Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Mon, 14 Jul 2025 23:38:07 +0200 Subject: [PATCH 321/324] hr: type fixes for 32-bit archs --- uspace/srv/bd/hr/raid1.c | 4 ++-- uspace/srv/bd/hr/raid5.c | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/uspace/srv/bd/hr/raid1.c b/uspace/srv/bd/hr/raid1.c index 99e7eb2efa..043813478e 100644 --- a/uspace/srv/bd/hr/raid1.c +++ b/uspace/srv/bd/hr/raid1.c @@ -668,8 +668,8 @@ static errno_t hr_raid1_rebuild(void *arg) hr_range_lock_t *rl = NULL; - HR_NOTE("\"%s\": REBUILD started on extent no. %zu at block %lu.\n", - vol->devname, rebuild_idx, ba); + HR_NOTE("\"%s\": REBUILD started on extent no. %zu at " + "block %" PRIu64 ".\n", vol->devname, rebuild_idx, ba); uint64_t written = 0; unsigned int percent, old_percent = 100; diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index 36170159a8..f524e74fc7 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -59,7 +59,7 @@ static void hr_raid5_vol_state_eval_forced(hr_volume_t *); static size_t hr_raid5_parity_extent(hr_level_t, hr_layout_t, size_t, uint64_t); static size_t hr_raid5_data_extent(hr_level_t, hr_layout_t, size_t, uint64_t, - uint64_t); + size_t); static errno_t hr_raid5_rebuild(void *); /* bdops */ @@ -744,7 +744,8 @@ static errno_t hr_raid5_rebuild(void *arg) hr_stripe_t *stripe = hr_create_stripes(vol, max_blks * vol->bsize, 1, false); - HR_NOTE("\"%s\": REBUILD started on extent no. %zu at block %lu.\n", + HR_NOTE("\"%s\": REBUILD started on extent no. %zu at " + "block %" PRIu64 ".\n", vol->devname, rebuild_idx, ba); uint64_t written = 0; From c1c1c41e4999dcd35e0f10f21068f69198546494 Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 15 Jul 2025 10:45:02 +0200 Subject: [PATCH 322/324] hr: add author's email address to RAID 5 files --- uspace/srv/bd/hr/io.c | 2 +- uspace/srv/bd/hr/io.h | 2 +- uspace/srv/bd/hr/parity_stripe.c | 2 +- uspace/srv/bd/hr/parity_stripe.h | 2 +- uspace/srv/bd/hr/raid5.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/uspace/srv/bd/hr/io.c b/uspace/srv/bd/hr/io.c index fec29fda29..8baa7c5706 100644 --- a/uspace/srv/bd/hr/io.c +++ b/uspace/srv/bd/hr/io.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025 Miroslav Cimerman + * Copyright (c) 2025 Miroslav Cimerman * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/uspace/srv/bd/hr/io.h b/uspace/srv/bd/hr/io.h index d0b1a14588..3bbfb81c9a 100644 --- a/uspace/srv/bd/hr/io.h +++ b/uspace/srv/bd/hr/io.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025 Miroslav Cimerman + * Copyright (c) 2025 Miroslav Cimerman * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/uspace/srv/bd/hr/parity_stripe.c b/uspace/srv/bd/hr/parity_stripe.c index d8f65295ec..88c3e747a7 100644 --- a/uspace/srv/bd/hr/parity_stripe.c +++ b/uspace/srv/bd/hr/parity_stripe.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025 Miroslav Cimerman + * Copyright (c) 2025 Miroslav Cimerman * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/uspace/srv/bd/hr/parity_stripe.h b/uspace/srv/bd/hr/parity_stripe.h index 6232379a8c..0f907b0a19 100644 --- a/uspace/srv/bd/hr/parity_stripe.h +++ b/uspace/srv/bd/hr/parity_stripe.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025 Miroslav Cimerman + * Copyright (c) 2025 Miroslav Cimerman * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/uspace/srv/bd/hr/raid5.c b/uspace/srv/bd/hr/raid5.c index f524e74fc7..7046115f0b 100644 --- a/uspace/srv/bd/hr/raid5.c +++ b/uspace/srv/bd/hr/raid5.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025 Miroslav Cimerman + * Copyright (c) 2025 Miroslav Cimerman * All rights reserved. * * Redistribution and use in source and binary forms, with or without From 25830c291dfc8036365fb28fae589ccfefbfbbfa Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Tue, 15 Jul 2025 18:13:43 +0200 Subject: [PATCH 323/324] hrctl: do not use devices/ prefix in usage --- uspace/app/hrctl/hrctl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/uspace/app/hrctl/hrctl.c b/uspace/app/hrctl/hrctl.c index c55d8e858c..215f453798 100644 --- a/uspace/app/hrctl/hrctl.c +++ b/uspace/app/hrctl/hrctl.c @@ -100,10 +100,10 @@ static const char usage_str[] = "\t\thrctl -c -f cfg.sif\n" "\t\thrctl --assemble disk1 disk2 disk3\n" "\t\thrctl -a\n" - "\t\thrctl -d devices/hr0\n" + "\t\thrctl -d hr0\n" "\t\thrctl -d\n" - "\t\thrctl --modify devices/hr0 --fail 0\n" - "\t\thrctl --modify devices/hr0 --hotspare disk4\n" + "\t\thrctl --modify hr0 --fail 0\n" + "\t\thrctl --modify hr0 --hotspare disk4\n" "\t\thrctl -s\n" "\n" "Notes:\n" From 73a2780b517696ad864ed16d1e48ed92a398324e Mon Sep 17 00:00:00 2001 From: Miroslav Cimerman Date: Wed, 16 Jul 2025 17:38:20 +0200 Subject: [PATCH 324/324] hr: remove old comments --- uspace/srv/bd/hr/hr.c | 4 ---- uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c | 5 ----- uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c | 5 ----- uspace/srv/bd/hr/metadata/foreign/md/md_p.h | 2 +- uspace/srv/bd/hr/metadata/native.c | 5 ----- uspace/srv/bd/hr/util.c | 2 -- 6 files changed, 1 insertion(+), 22 deletions(-) diff --git a/uspace/srv/bd/hr/hr.c b/uspace/srv/bd/hr/hr.c index 3ab5ea730a..f2938d4594 100644 --- a/uspace/srv/bd/hr/hr.c +++ b/uspace/srv/bd/hr/hr.c @@ -126,10 +126,6 @@ static void hr_create_srv(ipc_call_t *icall) */ for (i = 0; i < cfg->dev_no; i++) { if (cfg->devs[i] == 0) { - /* - * XXX: own error codes, no need to log this... - * its user error not service error - */ HR_ERROR("missing device provided for volume " "creation, aborting"); free(cfg); diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c index fb860160f4..176e117402 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c @@ -413,11 +413,6 @@ static errno_t meta_gmirror_get_block(service_id_t dev, void **rblock) return ENOMEM; rc = hr_read_direct(dev, blkno - 1, 1, block); - /* - * XXX: here maybe call vol state event or the state callback... - * - * but need to pass vol pointer - */ if (rc != EOK) { free(block); return rc; diff --git a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c index 857312f511..f173fc0e16 100644 --- a/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c +++ b/uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c @@ -351,11 +351,6 @@ static errno_t meta_gstripe_get_block(service_id_t dev, void **rblock) return ENOMEM; rc = hr_read_direct(dev, blkno - 1, 1, block); - /* - * XXX: here maybe call vol state event or the state callback... - * - * but need to pass vol pointer - */ if (rc != EOK) { free(block); return rc; diff --git a/uspace/srv/bd/hr/metadata/foreign/md/md_p.h b/uspace/srv/bd/hr/metadata/foreign/md/md_p.h index 7899d971ba..0f4fa22514 100644 --- a/uspace/srv/bd/hr/metadata/foreign/md/md_p.h +++ b/uspace/srv/bd/hr/metadata/foreign/md/md_p.h @@ -28,7 +28,7 @@ typedef uint8_t __u8; #define MD_OFFSET 8 #define MD_SIZE 2 -/* XXX: this is actually not used when assembling */ +/* this is actually not used when assembling */ #define MD_DATA_OFFSET 2048 #define MD_MAGIC 0xa92b4efc diff --git a/uspace/srv/bd/hr/metadata/native.c b/uspace/srv/bd/hr/metadata/native.c index c2441fa6bc..1062452508 100644 --- a/uspace/srv/bd/hr/metadata/native.c +++ b/uspace/srv/bd/hr/metadata/native.c @@ -494,11 +494,6 @@ static errno_t meta_native_get_block(service_id_t dev, void **rblock) return ENOMEM; rc = hr_read_direct(dev, blkno - 1, HR_NATIVE_META_SIZE, block); - /* - * XXX: here maybe call vol state event or the state callback... - * - * but need to pass vol pointer - */ if (rc != EOK) { free(block); return rc; diff --git a/uspace/srv/bd/hr/util.c b/uspace/srv/bd/hr/util.c index 442bfcfe63..b94508900e 100644 --- a/uspace/srv/bd/hr/util.c +++ b/uspace/srv/bd/hr/util.c @@ -752,8 +752,6 @@ static errno_t block_init_dev_list(list_t *list) errno_t rc = block_init(iter->svc_id); - /* already used as an extent of active volume */ - /* XXX: figure out how it is with hotspares too */ if (rc == EEXIST) { list_remove(cur_link); free_dev_list_member(iter);