Changeset e0bbecb in mainline


Ignore:
Timestamp:
2025-06-09T20:01:03Z (7 days ago)
Author:
Miroslav Cimerman <mc@…>
Children:
e2a8fd2
Parents:
431b513
Message:

hr: move state printing to hrctl

One IPC call is for short volume states printing
and other one for specific volume detailed info
printing.

Location:
uspace
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • uspace/app/hrctl/hrctl.c

    r431b513 re0bbecb  
    3434 */
    3535
     36#include <capa.h>
    3637#include <ctype.h>
    3738#include <errno.h>
     
    5152static errno_t fill_config_devs(int, char **, hr_config_t *);
    5253static errno_t get_vol_configs_from_sif(const char *, hr_config_t **, size_t *);
     54static int create_from_config(hr_t *, const char *);
     55static int create_from_argv(hr_t *, int, char **);
     56static int handle_create(hr_t *, int, char **);
     57static int assemble_from_config(hr_t *, const char *);
     58static int assemble_from_argv(hr_t *, int, char **);
     59static int handle_assemble(hr_t *, int, char **);
     60static int handle_disassemble(hr_t *, int, char **);
     61static int handle_modify(hr_t *, int, char **);
     62static errno_t print_vol_info(hr_vol_info_t *);
     63static int handle_state(hr_t *, int, char **);
    5364
    5465static const char usage_str[] =
     
    7687    "          -h, --hotspare device             add hotspare.\n"
    7788    "\n"
    78     "  -s, --state                               Display state of active volumes.\n"
     89    "  -s, --state [volume]                      Display state of active volume(s).\n"
    7990    "\n"
    8091    "level can be one of:\n"
     
    107118    "\t- volume name must be shorter than 32 characters\n"
    108119    "\t- automatic assembly and disassembly on nested volumes is UNDEFINED!\n";
    109 
    110 static void usage(void)
    111 {
    112         printf("%s", usage_str);
    113 }
    114 
    115 static errno_t fill_config_devs(int argc, char **argv, hr_config_t *cfg)
    116 {
    117         errno_t rc;
    118         size_t i;
    119 
    120         for (i = 0; i < HR_MAX_EXTENTS && optind < argc; i++) {
    121                 rc = loc_service_get_id(argv[optind], &cfg->devs[i], 0);
    122                 if (rc == ENOENT) {
    123                         printf(NAME ": device \"%s\" not found, aborting\n",
    124                             argv[optind]);
    125                         return ENOENT;
    126                 } else if (rc != EOK) {
    127                         printf(NAME ": error resolving device \"%s\", aborting\n",
    128                             argv[optind]);
    129                         return EINVAL;
    130                 }
    131                 optind++;
    132         }
    133 
    134         if (optind < argc) {
    135                 printf(NAME ": too many devices specified, max = %u\n",
    136                     HR_MAX_EXTENTS);
    137                 return ELIMIT;
    138         }
    139 
    140         cfg->dev_no = i;
    141 
    142         return EOK;
    143 }
    144 
    145 static errno_t get_vol_configs_from_sif(const char *path, hr_config_t **rcfgs,
    146     size_t *rcount)
    147 {
    148         errno_t rc;
    149         sif_doc_t *doc = NULL;
    150         sif_node_t *hrconfig_node;
    151         sif_node_t *root_node;
    152         sif_node_t *volume_node;
    153         sif_node_t *nextent;
    154         const char *ntype;
    155         const char *devname;
    156         const char *level_str;
    157         const char *extent_devname;
    158         hr_config_t *vol_configs = NULL;
    159 
    160         rc = sif_load(path, &doc);
    161         if (rc != EOK)
    162                 goto error;
    163 
    164         root_node = sif_get_root(doc);
    165 
    166         hrconfig_node = sif_node_first_child(root_node);
    167         ntype = sif_node_get_type(hrconfig_node);
    168         if (str_cmp(ntype, "hrconfig") != 0) {
    169                 rc = EINVAL;
    170                 goto error;
    171         }
    172 
    173         size_t vol_count = 0;
    174         volume_node = sif_node_first_child(hrconfig_node);
    175         while (volume_node) {
    176                 ntype = sif_node_get_type(volume_node);
    177                 if (str_cmp(ntype, "volume") != 0) {
    178                         rc = EINVAL;
    179                         goto error;
    180                 }
    181                 vol_configs = realloc(vol_configs,
    182                     (vol_count + 1) * sizeof(hr_config_t));
    183                 if (vol_configs == NULL) {
    184                         rc = ENOMEM;
    185                         goto error;
    186                 }
    187 
    188                 hr_config_t *cfg = vol_configs + vol_count;
    189 
    190                 devname = sif_node_get_attr(volume_node, "devname");
    191                 if (devname == NULL) {
    192                         rc = EINVAL;
    193                         goto error;
    194                 }
    195                 str_cpy(cfg->devname, sizeof(cfg->devname), devname);
    196 
    197                 level_str = sif_node_get_attr(volume_node, "level");
    198                 if (level_str == NULL)
    199                         cfg->level = HR_LVL_UNKNOWN;
    200                 else
    201                         cfg->level = strtol(level_str, NULL, 10);
    202 
    203                 nextent = sif_node_first_child(volume_node);
    204                 size_t i = 0;
    205                 while (nextent && i < HR_MAX_EXTENTS) {
    206                         ntype = sif_node_get_type(nextent);
    207                         if (str_cmp(ntype, "extent") != 0) {
    208                                 rc = EINVAL;
    209                                 goto error;
    210                         }
    211 
    212                         extent_devname = sif_node_get_attr(nextent, "devname");
    213                         if (extent_devname == NULL) {
    214                                 rc = EINVAL;
    215                                 goto error;
    216                         }
    217 
    218                         rc = loc_service_get_id(extent_devname, &cfg->devs[i], 0);
    219                         if (rc == ENOENT) {
    220                                 printf(NAME ": no device \"%s\", marking as missing\n",
    221                                     extent_devname);
    222                                 cfg->devs[i] = 0;
    223                                 rc = EOK;
    224                         } else if (rc != EOK) {
    225                                 printf(NAME ": error resolving device \"%s\", aborting\n",
    226                                     extent_devname);
    227                                 goto error;
    228                         }
    229 
    230                         nextent = sif_node_next_child(nextent);
    231                         i++;
    232                 }
    233 
    234                 if (i > HR_MAX_EXTENTS) {
    235                         printf(NAME ": too many devices specified in volume \"%s\", "
    236                             "skipping\n", devname);
    237                         memset(&vol_configs[vol_count], 0, sizeof(hr_config_t));
    238                 } else {
    239                         cfg->dev_no = i;
    240                         vol_count++;
    241                 }
    242 
    243                 volume_node = sif_node_next_child(volume_node);
    244         }
    245 
    246         if (rc == EOK) {
    247                 if (rcount)
    248                         *rcount = vol_count;
    249                 if (rcfgs)
    250                         *rcfgs = vol_configs;
    251         }
    252 error:
    253         if (doc != NULL)
    254                 sif_delete(doc);
    255         if (rc != EOK) {
    256                 if (vol_configs)
    257                         free(vol_configs);
    258         }
    259         return rc;
    260 }
    261 
    262 static int create_from_config(hr_t *hr, const char *config_path)
    263 {
    264         hr_config_t *vol_configs = NULL;
    265         size_t vol_count = 0;
    266         errno_t rc = get_vol_configs_from_sif(config_path, &vol_configs,
    267             &vol_count);
    268         if (rc != EOK) {
    269                 printf(NAME ": config parsing failed\n");
    270                 return EXIT_FAILURE;
    271         }
    272 
    273         for (size_t i = 0; i < vol_count; i++) {
    274                 rc = hr_create(hr, &vol_configs[i]);
    275                 if (rc != EOK) {
    276                         printf(NAME ": creation of volume \"%s\" failed: %s, "
    277                             "but continuing\n",
    278                             vol_configs[i].devname, str_error(rc));
    279                 } else {
    280                         printf(NAME ": volume \"%s\" successfully created\n",
    281                             vol_configs[i].devname);
    282                 }
    283         }
    284 
    285         free(vol_configs);
    286         return EXIT_SUCCESS;
    287 }
    288 
    289 static int create_from_argv(hr_t *hr, int argc, char **argv)
    290 {
    291         /* we need name + --level + arg + at least one extent */
    292         if (optind + 3 >= argc) {
    293                 printf(NAME ": not enough arguments\n");
    294                 return EXIT_FAILURE;
    295         }
    296 
    297         hr_config_t *vol_config = calloc(1, sizeof(hr_config_t));
    298         if (vol_config == NULL) {
    299                 printf(NAME ": not enough memory\n");
    300                 return EXIT_FAILURE;
    301         }
    302 
    303         const char *name = argv[optind++];
    304         if (str_size(name) >= HR_DEVNAME_LEN) {
    305                 printf(NAME ": devname must be less then 32 bytes.\n");
    306                 goto error;
    307         }
    308 
    309         str_cpy(vol_config->devname, HR_DEVNAME_LEN, name);
    310 
    311         const char *level_opt = argv[optind++];
    312         if (str_cmp(level_opt, "--level") != 0 &&
    313             str_cmp(level_opt, "-l") != 0) {
    314                 printf(NAME ": unknown option \"%s\"\n", level_opt);
    315                 goto error;
    316         }
    317 
    318         const char *level_str = argv[optind++];
    319         if (str_size(level_str) == 1 && isdigit(level_str[0])) {
    320                 vol_config->level = strtol(level_str, NULL, 10);
    321         } else {
    322                 if (str_cmp(level_str, "mirror") == 0 ||
    323                     str_cmp(level_str, "mirroring") == 0) {
    324                         vol_config->level = HR_LVL_1;
    325                 } else if (str_cmp(level_str, "stripe") == 0 ||
    326                     str_cmp(level_str, "striping") == 0) {
    327                         vol_config->level = HR_LVL_0;
    328                 } else if (str_cmp(level_str, "parity") == 0 ||
    329                     str_cmp(level_str, "parity_distributed") == 0) {
    330                         vol_config->level = HR_LVL_5;
    331                 } else if (str_cmp(level_str, "parity_dedicated") == 0) {
    332                         vol_config->level = HR_LVL_4;
    333                 } else {
    334                         printf(NAME ": unknown level \"%s\"\n", level_str);
    335                         goto error;
    336                 }
    337         }
    338 
    339         errno_t rc = fill_config_devs(argc, argv, vol_config);
    340         if (rc != EOK)
    341                 goto error;
    342 
    343         rc = hr_create(hr, vol_config);
    344         if (rc != EOK) {
    345                 printf(NAME ": creation failed: %s\n", str_error(rc));
    346                 goto error;
    347         } else {
    348                 printf(NAME ": volume \"%s\" successfully created\n",
    349                     vol_config->devname);
    350         }
    351 
    352         free(vol_config);
    353         return EXIT_SUCCESS;
    354 error:
    355         free(vol_config);
    356         return EXIT_FAILURE;
    357 }
    358 
    359 static int handle_create(hr_t *hr, int argc, char **argv)
    360 {
    361         int rc;
    362 
    363         if (optind >= argc) {
    364                 printf(NAME ": no arguments to --create\n");
    365                 return EXIT_FAILURE;
    366         }
    367 
    368         if (str_cmp(argv[optind], "-f") == 0) {
    369                 optind++;
    370                 if (optind >= argc) {
    371                         printf(NAME ": not enough arguments\n");
    372                         return EXIT_FAILURE;
    373                 }
    374 
    375                 const char *config_path = argv[optind++];
    376 
    377                 if (optind < argc) {
    378                         printf(NAME ": unexpected arguments\n");
    379                         return EXIT_FAILURE;
    380                 }
    381 
    382                 rc = create_from_config(hr, config_path);
    383         } else {
    384                 rc = create_from_argv(hr, argc, argv);
    385         }
    386 
    387         return rc;
    388 }
    389 
    390 static int assemble_from_config(hr_t *hr, const char *config_path)
    391 {
    392         hr_config_t *vol_configs = NULL;
    393         size_t vol_count = 0;
    394         errno_t rc = get_vol_configs_from_sif(config_path, &vol_configs,
    395             &vol_count);
    396         if (rc != EOK) {
    397                 printf(NAME ": config parsing failed\n");
    398                 return EXIT_FAILURE;
    399         }
    400 
    401         size_t cnt = 0;
    402         for (size_t i = 0; i < vol_count; i++) {
    403                 size_t tmpcnt = 0;
    404                 (void)hr_assemble(hr, &vol_configs[i], &tmpcnt);
    405                 cnt += tmpcnt;
    406         }
    407 
    408         printf(NAME ": assembled %zu volumes\n", cnt);
    409 
    410         free(vol_configs);
    411         return EXIT_SUCCESS;
    412 }
    413 
    414 static int assemble_from_argv(hr_t *hr, int argc, char **argv)
    415 {
    416         hr_config_t *vol_config = calloc(1, sizeof(hr_config_t));
    417         if (vol_config == NULL) {
    418                 printf(NAME ": not enough memory\n");
    419                 return ENOMEM;
    420         }
    421 
    422         errno_t rc = fill_config_devs(argc, argv, vol_config);
    423         if (rc != EOK)
    424                 goto error;
    425 
    426         size_t cnt;
    427         rc = hr_assemble(hr, vol_config, &cnt);
    428         if (rc != EOK) {
    429                 printf(NAME ": assmeble failed: %s\n", str_error(rc));
    430                 goto error;
    431         }
    432 
    433         printf("hrctl: assembled %zu volumes\n", cnt);
    434 
    435         free(vol_config);
    436         return EXIT_SUCCESS;
    437 error:
    438         free(vol_config);
    439         return EXIT_FAILURE;
    440 }
    441 
    442 static int handle_assemble(hr_t *hr, int argc, char **argv)
    443 {
    444         int rc;
    445 
    446         if (optind >= argc) {
    447                 size_t cnt;
    448                 errno_t rc = hr_auto_assemble(hr, &cnt);
    449                 if (rc != EOK) {
    450                         /* XXX: here have own error codes */
    451                         printf("hrctl: auto assemble rc: %s\n", str_error(rc));
    452                         return EXIT_FAILURE;
    453                 }
    454 
    455                 printf(NAME ": auto assembled %zu volumes\n", cnt);
    456                 return EXIT_SUCCESS;
    457         }
    458 
    459         if (str_cmp(argv[optind], "-f") == 0) {
    460                 if (++optind >= argc) {
    461                         printf(NAME ": not enough arguments\n");
    462                         return EXIT_FAILURE;
    463                 }
    464                 const char *config_path = argv[optind++];
    465 
    466                 if (optind < argc) {
    467                         printf(NAME ": unexpected arguments\n");
    468                         return EXIT_FAILURE;
    469                 }
    470 
    471                 rc = assemble_from_config(hr, config_path);
    472         } else {
    473                 rc = assemble_from_argv(hr, argc, argv);
    474         }
    475 
    476         return rc;
    477 }
    478 
    479 static int handle_disassemble(hr_t *hr, int argc, char **argv)
    480 {
    481         if (optind >= argc) {
    482                 errno_t rc = hr_stop_all(hr);
    483                 if (rc != EOK) {
    484                         printf(NAME ": stopping some volumes failed: %s\n",
    485                             str_error(rc));
    486                         return EXIT_FAILURE;
    487                 }
    488                 return EXIT_SUCCESS;
    489         }
    490 
    491         if (optind + 1 < argc) {
    492                 printf(NAME ": only 1 device can be manually specified\n");
    493                 return EXIT_FAILURE;
    494         }
    495 
    496         const char *devname = argv[optind++];
    497 
    498         errno_t rc = hr_stop(hr, devname);
    499         if (rc != EOK) {
    500                 printf(NAME ": disassembly of device \"%s\" failed: %s\n",
    501                     devname, str_error(rc));
    502                 return EXIT_FAILURE;
    503         }
    504 
    505         return EXIT_SUCCESS;
    506 }
    507 
    508 static int handle_modify(hr_t *hr, int argc, char **argv)
    509 {
    510         if (optind >= argc) {
    511                 printf(NAME ": no arguments to --modify\n");
    512                 return EXIT_FAILURE;
    513         }
    514 
    515         const char *volname = argv[optind++];
    516 
    517         /* at least 1 option and its agument */
    518         if (optind + 1 >= argc) {
    519                 printf(NAME ": not enough arguments\n");
    520                 return EXIT_FAILURE;
    521         }
    522 
    523         if (optind + 2 < argc) {
    524                 printf(NAME ": unexpected arguments\n");
    525                 return EXIT_FAILURE;
    526         }
    527 
    528         if (str_cmp(argv[optind], "--fail") == 0 ||
    529             str_cmp(argv[optind], "-f") == 0) {
    530                 optind++;
    531                 unsigned long extent = strtol(argv[optind++], NULL, 10);
    532                 errno_t rc = hr_fail_extent(hr, volname, extent);
    533                 if (rc != EOK) {
    534                         printf(NAME ": failing extent failed: %s\n",
    535                             str_error(rc));
    536                         return EXIT_FAILURE;
    537                 }
    538         } else if (str_cmp(argv[optind], "--hotspare") == 0 ||
    539             str_cmp(argv[optind], "-h") == 0) {
    540                 optind++;
    541                 errno_t rc = hr_add_hotspare(hr, volname, argv[optind++]);
    542                 if (rc != EOK) {
    543                         printf(NAME ": adding hotspare failed: %s\n",
    544                             str_error(rc));
    545                         return EXIT_FAILURE;
    546                 }
    547         } else {
    548                 printf(NAME ": unknown argument\n");
    549                 return EXIT_FAILURE;
    550         }
    551 
    552         return EXIT_SUCCESS;
    553 }
    554 
    555 static int handle_state(hr_t *hr, int argc, char **argv)
    556 {
    557         (void)argc;
    558         (void)argv;
    559 
    560         errno_t rc = hr_print_state(hr);
    561         if (rc != EOK) {
    562                 printf(NAME ": state printing failed: %s\n", str_error(rc));
    563                 return EXIT_FAILURE;
    564         }
    565 
    566         return EXIT_SUCCESS;
    567 }
    568120
    569121int main(int argc, char **argv)
     
    629181}
    630182
     183static void usage(void)
     184{
     185        printf("%s", usage_str);
     186}
     187
     188static errno_t fill_config_devs(int argc, char **argv, hr_config_t *cfg)
     189{
     190        errno_t rc;
     191        size_t i;
     192
     193        for (i = 0; i < HR_MAX_EXTENTS && optind < argc; i++) {
     194                rc = loc_service_get_id(argv[optind], &cfg->devs[i], 0);
     195                if (rc == ENOENT) {
     196                        printf(NAME ": device \"%s\" not found, aborting\n",
     197                            argv[optind]);
     198                        return ENOENT;
     199                } else if (rc != EOK) {
     200                        printf(NAME ": error resolving device \"%s\", aborting\n",
     201                            argv[optind]);
     202                        return EINVAL;
     203                }
     204                optind++;
     205        }
     206
     207        if (optind < argc) {
     208                printf(NAME ": too many devices specified, max = %u\n",
     209                    HR_MAX_EXTENTS);
     210                return ELIMIT;
     211        }
     212
     213        cfg->dev_no = i;
     214
     215        return EOK;
     216}
     217
     218static errno_t get_vol_configs_from_sif(const char *path, hr_config_t **rcfgs,
     219    size_t *rcount)
     220{
     221        errno_t rc;
     222        sif_doc_t *doc = NULL;
     223        sif_node_t *hrconfig_node;
     224        sif_node_t *root_node;
     225        sif_node_t *volume_node;
     226        sif_node_t *nextent;
     227        const char *ntype;
     228        const char *devname;
     229        const char *level_str;
     230        const char *extent_devname;
     231        hr_config_t *vol_configs = NULL;
     232
     233        rc = sif_load(path, &doc);
     234        if (rc != EOK)
     235                goto error;
     236
     237        root_node = sif_get_root(doc);
     238
     239        hrconfig_node = sif_node_first_child(root_node);
     240        ntype = sif_node_get_type(hrconfig_node);
     241        if (str_cmp(ntype, "hrconfig") != 0) {
     242                rc = EINVAL;
     243                goto error;
     244        }
     245
     246        size_t vol_count = 0;
     247        volume_node = sif_node_first_child(hrconfig_node);
     248        while (volume_node) {
     249                ntype = sif_node_get_type(volume_node);
     250                if (str_cmp(ntype, "volume") != 0) {
     251                        rc = EINVAL;
     252                        goto error;
     253                }
     254                vol_configs = realloc(vol_configs,
     255                    (vol_count + 1) * sizeof(hr_config_t));
     256                if (vol_configs == NULL) {
     257                        rc = ENOMEM;
     258                        goto error;
     259                }
     260
     261                hr_config_t *cfg = vol_configs + vol_count;
     262
     263                devname = sif_node_get_attr(volume_node, "devname");
     264                if (devname == NULL) {
     265                        rc = EINVAL;
     266                        goto error;
     267                }
     268                str_cpy(cfg->devname, sizeof(cfg->devname), devname);
     269
     270                level_str = sif_node_get_attr(volume_node, "level");
     271                if (level_str == NULL)
     272                        cfg->level = HR_LVL_UNKNOWN;
     273                else
     274                        cfg->level = strtol(level_str, NULL, 10);
     275
     276                nextent = sif_node_first_child(volume_node);
     277                size_t i = 0;
     278                while (nextent && i < HR_MAX_EXTENTS) {
     279                        ntype = sif_node_get_type(nextent);
     280                        if (str_cmp(ntype, "extent") != 0) {
     281                                rc = EINVAL;
     282                                goto error;
     283                        }
     284
     285                        extent_devname = sif_node_get_attr(nextent, "devname");
     286                        if (extent_devname == NULL) {
     287                                rc = EINVAL;
     288                                goto error;
     289                        }
     290
     291                        rc = loc_service_get_id(extent_devname, &cfg->devs[i], 0);
     292                        if (rc == ENOENT) {
     293                                printf(NAME ": no device \"%s\", marking as missing\n",
     294                                    extent_devname);
     295                                cfg->devs[i] = 0;
     296                                rc = EOK;
     297                        } else if (rc != EOK) {
     298                                printf(NAME ": error resolving device \"%s\", aborting\n",
     299                                    extent_devname);
     300                                goto error;
     301                        }
     302
     303                        nextent = sif_node_next_child(nextent);
     304                        i++;
     305                }
     306
     307                if (i > HR_MAX_EXTENTS) {
     308                        printf(NAME ": too many devices specified in volume \"%s\", "
     309                            "skipping\n", devname);
     310                        memset(&vol_configs[vol_count], 0, sizeof(hr_config_t));
     311                } else {
     312                        cfg->dev_no = i;
     313                        vol_count++;
     314                }
     315
     316                volume_node = sif_node_next_child(volume_node);
     317        }
     318
     319        if (rc == EOK) {
     320                if (rcount)
     321                        *rcount = vol_count;
     322                if (rcfgs)
     323                        *rcfgs = vol_configs;
     324        }
     325error:
     326        if (doc != NULL)
     327                sif_delete(doc);
     328        if (rc != EOK) {
     329                if (vol_configs)
     330                        free(vol_configs);
     331        }
     332        return rc;
     333}
     334
     335static int create_from_config(hr_t *hr, const char *config_path)
     336{
     337        hr_config_t *vol_configs = NULL;
     338        size_t vol_count = 0;
     339        errno_t rc = get_vol_configs_from_sif(config_path, &vol_configs,
     340            &vol_count);
     341        if (rc != EOK) {
     342                printf(NAME ": config parsing failed\n");
     343                return EXIT_FAILURE;
     344        }
     345
     346        for (size_t i = 0; i < vol_count; i++) {
     347                rc = hr_create(hr, &vol_configs[i]);
     348                if (rc != EOK) {
     349                        printf(NAME ": creation of volume \"%s\" failed: %s, "
     350                            "but continuing\n",
     351                            vol_configs[i].devname, str_error(rc));
     352                } else {
     353                        printf(NAME ": volume \"%s\" successfully created\n",
     354                            vol_configs[i].devname);
     355                }
     356        }
     357
     358        free(vol_configs);
     359        return EXIT_SUCCESS;
     360}
     361
     362static int create_from_argv(hr_t *hr, int argc, char **argv)
     363{
     364        /* we need name + --level + arg + at least one extent */
     365        if (optind + 3 >= argc) {
     366                printf(NAME ": not enough arguments\n");
     367                return EXIT_FAILURE;
     368        }
     369
     370        hr_config_t *vol_config = calloc(1, sizeof(hr_config_t));
     371        if (vol_config == NULL) {
     372                printf(NAME ": not enough memory\n");
     373                return EXIT_FAILURE;
     374        }
     375
     376        const char *name = argv[optind++];
     377        if (str_size(name) >= HR_DEVNAME_LEN) {
     378                printf(NAME ": devname must be less then 32 bytes.\n");
     379                goto error;
     380        }
     381
     382        str_cpy(vol_config->devname, HR_DEVNAME_LEN, name);
     383
     384        const char *level_opt = argv[optind++];
     385        if (str_cmp(level_opt, "--level") != 0 &&
     386            str_cmp(level_opt, "-l") != 0) {
     387                printf(NAME ": unknown option \"%s\"\n", level_opt);
     388                goto error;
     389        }
     390
     391        const char *level_str = argv[optind++];
     392        if (str_size(level_str) == 1 && isdigit(level_str[0])) {
     393                vol_config->level = strtol(level_str, NULL, 10);
     394        } else {
     395                if (str_cmp(level_str, "mirror") == 0 ||
     396                    str_cmp(level_str, "mirroring") == 0) {
     397                        vol_config->level = HR_LVL_1;
     398                } else if (str_cmp(level_str, "stripe") == 0 ||
     399                    str_cmp(level_str, "striping") == 0) {
     400                        vol_config->level = HR_LVL_0;
     401                } else if (str_cmp(level_str, "parity") == 0 ||
     402                    str_cmp(level_str, "parity_distributed") == 0) {
     403                        vol_config->level = HR_LVL_5;
     404                } else if (str_cmp(level_str, "parity_dedicated") == 0) {
     405                        vol_config->level = HR_LVL_4;
     406                } else {
     407                        printf(NAME ": unknown level \"%s\"\n", level_str);
     408                        goto error;
     409                }
     410        }
     411
     412        errno_t rc = fill_config_devs(argc, argv, vol_config);
     413        if (rc != EOK)
     414                goto error;
     415
     416        rc = hr_create(hr, vol_config);
     417        if (rc != EOK) {
     418                printf(NAME ": creation failed: %s\n", str_error(rc));
     419                goto error;
     420        } else {
     421                printf(NAME ": volume \"%s\" successfully created\n",
     422                    vol_config->devname);
     423        }
     424
     425        free(vol_config);
     426        return EXIT_SUCCESS;
     427error:
     428        free(vol_config);
     429        return EXIT_FAILURE;
     430}
     431
     432static int handle_create(hr_t *hr, int argc, char **argv)
     433{
     434        int rc;
     435
     436        if (optind >= argc) {
     437                printf(NAME ": no arguments to --create\n");
     438                return EXIT_FAILURE;
     439        }
     440
     441        if (str_cmp(argv[optind], "-f") == 0) {
     442                optind++;
     443                if (optind >= argc) {
     444                        printf(NAME ": not enough arguments\n");
     445                        return EXIT_FAILURE;
     446                }
     447
     448                const char *config_path = argv[optind++];
     449
     450                if (optind < argc) {
     451                        printf(NAME ": unexpected arguments\n");
     452                        return EXIT_FAILURE;
     453                }
     454
     455                rc = create_from_config(hr, config_path);
     456        } else {
     457                rc = create_from_argv(hr, argc, argv);
     458        }
     459
     460        return rc;
     461}
     462
     463static int assemble_from_config(hr_t *hr, const char *config_path)
     464{
     465        hr_config_t *vol_configs = NULL;
     466        size_t vol_count = 0;
     467        errno_t rc = get_vol_configs_from_sif(config_path, &vol_configs,
     468            &vol_count);
     469        if (rc != EOK) {
     470                printf(NAME ": config parsing failed\n");
     471                return EXIT_FAILURE;
     472        }
     473
     474        size_t cnt = 0;
     475        for (size_t i = 0; i < vol_count; i++) {
     476                size_t tmpcnt = 0;
     477                (void)hr_assemble(hr, &vol_configs[i], &tmpcnt);
     478                cnt += tmpcnt;
     479        }
     480
     481        printf(NAME ": assembled %zu volumes\n", cnt);
     482
     483        free(vol_configs);
     484        return EXIT_SUCCESS;
     485}
     486
     487static int assemble_from_argv(hr_t *hr, int argc, char **argv)
     488{
     489        hr_config_t *vol_config = calloc(1, sizeof(hr_config_t));
     490        if (vol_config == NULL) {
     491                printf(NAME ": not enough memory\n");
     492                return ENOMEM;
     493        }
     494
     495        errno_t rc = fill_config_devs(argc, argv, vol_config);
     496        if (rc != EOK)
     497                goto error;
     498
     499        size_t cnt;
     500        rc = hr_assemble(hr, vol_config, &cnt);
     501        if (rc != EOK) {
     502                printf(NAME ": assmeble failed: %s\n", str_error(rc));
     503                goto error;
     504        }
     505
     506        printf("hrctl: assembled %zu volumes\n", cnt);
     507
     508        free(vol_config);
     509        return EXIT_SUCCESS;
     510error:
     511        free(vol_config);
     512        return EXIT_FAILURE;
     513}
     514
     515static int handle_assemble(hr_t *hr, int argc, char **argv)
     516{
     517        int rc;
     518
     519        if (optind >= argc) {
     520                size_t cnt;
     521                errno_t rc = hr_auto_assemble(hr, &cnt);
     522                if (rc != EOK) {
     523                        /* XXX: here have own error codes */
     524                        printf("hrctl: auto assemble rc: %s\n", str_error(rc));
     525                        return EXIT_FAILURE;
     526                }
     527
     528                printf(NAME ": auto assembled %zu volumes\n", cnt);
     529                return EXIT_SUCCESS;
     530        }
     531
     532        if (str_cmp(argv[optind], "-f") == 0) {
     533                if (++optind >= argc) {
     534                        printf(NAME ": not enough arguments\n");
     535                        return EXIT_FAILURE;
     536                }
     537                const char *config_path = argv[optind++];
     538
     539                if (optind < argc) {
     540                        printf(NAME ": unexpected arguments\n");
     541                        return EXIT_FAILURE;
     542                }
     543
     544                rc = assemble_from_config(hr, config_path);
     545        } else {
     546                rc = assemble_from_argv(hr, argc, argv);
     547        }
     548
     549        return rc;
     550}
     551
     552static int handle_disassemble(hr_t *hr, int argc, char **argv)
     553{
     554        if (optind >= argc) {
     555                errno_t rc = hr_stop_all(hr);
     556                if (rc != EOK) {
     557                        printf(NAME ": stopping some volumes failed: %s\n",
     558                            str_error(rc));
     559                        return EXIT_FAILURE;
     560                }
     561                return EXIT_SUCCESS;
     562        }
     563
     564        if (optind + 1 < argc) {
     565                printf(NAME ": only 1 device can be manually specified\n");
     566                return EXIT_FAILURE;
     567        }
     568
     569        const char *devname = argv[optind++];
     570
     571        errno_t rc = hr_stop(hr, devname);
     572        if (rc != EOK) {
     573                printf(NAME ": disassembly of device \"%s\" failed: %s\n",
     574                    devname, str_error(rc));
     575                return EXIT_FAILURE;
     576        }
     577
     578        return EXIT_SUCCESS;
     579}
     580
     581static int handle_modify(hr_t *hr, int argc, char **argv)
     582{
     583        if (optind >= argc) {
     584                printf(NAME ": no arguments to --modify\n");
     585                return EXIT_FAILURE;
     586        }
     587
     588        const char *volname = argv[optind++];
     589
     590        /* at least 1 option and its agument */
     591        if (optind + 1 >= argc) {
     592                printf(NAME ": not enough arguments\n");
     593                return EXIT_FAILURE;
     594        }
     595
     596        if (optind + 2 < argc) {
     597                printf(NAME ": unexpected arguments\n");
     598                return EXIT_FAILURE;
     599        }
     600
     601        if (str_cmp(argv[optind], "--fail") == 0 ||
     602            str_cmp(argv[optind], "-f") == 0) {
     603                optind++;
     604                unsigned long extent = strtol(argv[optind++], NULL, 10);
     605                errno_t rc = hr_fail_extent(hr, volname, extent);
     606                if (rc != EOK) {
     607                        printf(NAME ": failing extent failed: %s\n",
     608                            str_error(rc));
     609                        return EXIT_FAILURE;
     610                }
     611        } else if (str_cmp(argv[optind], "--hotspare") == 0 ||
     612            str_cmp(argv[optind], "-h") == 0) {
     613                optind++;
     614                errno_t rc = hr_add_hotspare(hr, volname, argv[optind++]);
     615                if (rc != EOK) {
     616                        printf(NAME ": adding hotspare failed: %s\n",
     617                            str_error(rc));
     618                        return EXIT_FAILURE;
     619                }
     620        } else {
     621                printf(NAME ": unknown argument\n");
     622                return EXIT_FAILURE;
     623        }
     624
     625        return EXIT_SUCCESS;
     626}
     627
     628static errno_t print_vol_info(hr_vol_info_t *info)
     629{
     630        errno_t rc;
     631        size_t i;
     632        hr_extent_t *ext;
     633        const char *devname;
     634
     635        printf("volume: \"%s\" (%" PRIun ")\n", info->devname, info->svc_id);
     636
     637        printf("|   metadata type: %s\n",
     638            hr_get_metadata_type_str(info->meta_type));
     639        printf("|           level: %s\n", hr_get_level_str(info->level));
     640        if (info->layout != HR_RLQ_NONE)
     641                printf("|          layout: %s\n",
     642                    hr_get_layout_str(info->layout));
     643
     644        if (info->strip_size > 0) {
     645                if (info->strip_size < 1024) {
     646                        printf("|      strip size: %" PRIu32 "B\n",
     647                            info->strip_size);
     648                } else {
     649                        printf("|      strip size: %" PRIu32 "KiB\n",
     650                            info->strip_size / 1024);
     651                }
     652        }
     653
     654        printf("|  no. of extents: %zu\n", info->extent_no);
     655        printf("|no. of hotspares: %zu\n", info->hotspare_no);
     656        printf("|number of blocks: %" PRIu64 "\n", info->data_blkno);
     657        printf("|      block size: %zuB\n", info->bsize);
     658
     659        capa_spec_t capa;
     660        char *scapa = NULL;
     661        capa_from_blocks(info->data_blkno, info->bsize, &capa);
     662        capa_simplify(&capa);
     663        rc = capa_format(&capa, &scapa);
     664        if (rc != EOK) {
     665                printf(NAME ": failed to format capacity: %s\n", str_error(rc));
     666                return rc;
     667        }
     668
     669        printf("| volume capacity: %s\n", scapa);
     670
     671        free(scapa);
     672
     673        printf("|           state: %s\n", hr_get_vol_state_str(info->state));
     674        printf("|         extents:\n");
     675
     676        for (i = 0; i < info->extent_no; i++) {
     677                ext = &info->extents[i];
     678                char *tmpname = NULL;
     679                if (ext->state == HR_EXT_MISSING || ext->state == HR_EXT_NONE) {
     680                        devname = "MISSING";
     681                } else {
     682                        rc = loc_service_get_name(ext->svc_id, &tmpname);
     683                        if (rc != EOK)
     684                                devname = "MISSING";
     685                        else
     686                                devname = tmpname;
     687                }
     688                printf("|                  %zu %s\n", i, hr_get_ext_state_str(ext->state));
     689                printf("|                      %s\n", devname);
     690                if (tmpname != NULL)
     691                        free(tmpname);
     692        }
     693
     694        if (info->hotspare_no == 0)
     695                return EOK;
     696
     697        printf("|       hotspares:\n");
     698        for (i = 0; i < info->hotspare_no; i++) {
     699                ext = &info->hotspares[i];
     700                char *tmpname;
     701                if (ext->state == HR_EXT_MISSING || ext->state == HR_EXT_NONE) {
     702                        devname = "MISSING";
     703                } else {
     704                        rc = loc_service_get_name(ext->svc_id, &tmpname);
     705                        if (rc != EOK)
     706                                devname = "MISSING";
     707                        else
     708                                devname = tmpname;
     709                }
     710                printf("|                  %zu %s\n", i, hr_get_ext_state_str(ext->state));
     711                printf("|                      %s\n", devname);
     712                if (tmpname != NULL)
     713                        free(tmpname);
     714        }
     715
     716        return EOK;
     717}
     718
     719static int handle_state(hr_t *hr, int argc, char **argv)
     720{
     721        errno_t rc;
     722        size_t cnt;
     723        hr_pair_vol_state_t *pairs = NULL;
     724        char *devname;
     725
     726        /* print state of all volumes */
     727        if (optind >= argc) {
     728                rc = hr_get_vol_states(hr, &pairs, &cnt);
     729                if (rc != EOK) {
     730                        printf(NAME ": failed getting state of volumes: %s\n",
     731                            str_error(rc));
     732                        return EXIT_FAILURE;
     733                }
     734
     735                if (cnt == 0) {
     736                        printf(NAME ": no active volumes\n");
     737                        return EXIT_SUCCESS;
     738                }
     739
     740                for (size_t i = 0; i < cnt; i++) {
     741                        service_id_t svc_id = pairs[i].svc_id;
     742                        hr_vol_state_t state = pairs[i].state;
     743                        rc = loc_service_get_name(svc_id, &devname);
     744                        if (rc != EOK) {
     745                                printf(NAME ": getting service name failed: "
     746                                    "%s\n", str_error(rc));
     747                                return EXIT_FAILURE;
     748                        }
     749                        printf("volume \"%s\" (%" PRIun ") %s\n", devname,
     750                            svc_id, hr_get_vol_state_str(state));
     751
     752                        free(devname);
     753                }
     754                free(pairs);
     755
     756                return EXIT_SUCCESS;
     757        }
     758
     759        /* print volume info of requested volumes */
     760        while (optind < argc) {
     761                service_id_t svc_id;
     762                devname = argv[optind++];
     763                rc = loc_service_get_id(devname, &svc_id, 0);
     764                if (rc != EOK) {
     765                        printf(NAME ": getting service id of \"%s\" failed: "
     766                            "%s\n", devname, str_error(rc));
     767                        return EXIT_FAILURE;
     768                }
     769
     770                hr_vol_info_t info;
     771                rc = hr_get_vol_info(hr, svc_id, &info);
     772                if (rc != EOK) {
     773                        printf(NAME ": getting volume info failed: %s\n",
     774                            str_error(rc));
     775                        return EXIT_FAILURE;
     776                }
     777
     778                rc = print_vol_info(&info);
     779                if (rc != EOK) {
     780                        printf(NAME ": volume info printing failed: %s\n",
     781                            str_error(rc));
     782                        return EXIT_FAILURE;
     783                }
     784        }
     785
     786        return EXIT_SUCCESS;
     787}
     788
    631789/** @}
    632790 */
  • uspace/app/hrctl/meson.build

    r431b513 re0bbecb  
    11#
    2 # Copyright (c) 2024 Miroslav Cimerman
     2# Copyright (c) 2025 Miroslav Cimerman
    33# All rights reserved.
    44#
  • uspace/lib/device/include/hr.h

    r431b513 re0bbecb  
    8282} hr_ext_state_t;
    8383
     84typedef enum {
     85        HR_METADATA_NATIVE = 0,
     86        HR_METADATA_GEOM_MIRROR,
     87        HR_METADATA_GEOM_STRIPE,
     88        HR_METADATA_SOFTRAID,
     89        HR_METADATA_LAST_DUMMY
     90} hr_metadata_type_t;
     91
    8492typedef struct hr {
    8593        async_sess_t *sess;
     
    98106} hr_extent_t;
    99107
     108typedef struct hr_pair_vol_state {
     109        service_id_t svc_id;
     110        hr_vol_state_t state;
     111} hr_pair_vol_state_t;
     112
    100113typedef struct hr_vol_info {
     114        char devname[HR_DEVNAME_LEN];
     115        service_id_t svc_id;
     116        hr_level_t level;
    101117        hr_extent_t extents[HR_MAX_EXTENTS];
    102118        hr_extent_t hotspares[HR_MAX_HOTSPARES];
    103119        size_t extent_no;
    104120        size_t hotspare_no;
    105         service_id_t svc_id;
    106         hr_level_t level;
    107         uint64_t nblocks;
     121        uint64_t data_blkno;
    108122        uint32_t strip_size;
    109123        size_t bsize;
    110124        hr_vol_state_t state;
    111         uint8_t layout;
     125        hr_layout_t layout;
     126        hr_metadata_type_t meta_type;
     127        /* TODO: add rebuild pos */
    112128} hr_vol_info_t;
    113 
    114 typedef enum {
    115         HR_METADATA_NATIVE = 0,
    116         HR_METADATA_GEOM_MIRROR,
    117         HR_METADATA_GEOM_STRIPE,
    118         HR_METADATA_SOFTRAID,
    119         HR_METADATA_LAST_DUMMY
    120 } hr_metadata_type_t;
    121129
    122130extern errno_t hr_sess_init(hr_t **);
     
    129137extern errno_t hr_fail_extent(hr_t *, const char *, unsigned long);
    130138extern errno_t hr_add_hotspare(hr_t *, const char *, const char *);
    131 extern errno_t hr_print_state(hr_t *);
     139extern errno_t hr_get_vol_states(hr_t *, hr_pair_vol_state_t **, size_t *);
     140extern errno_t hr_get_vol_info(hr_t *, service_id_t, hr_vol_info_t *);
    132141extern const char *hr_get_vol_state_str(hr_vol_state_t);
    133142extern const char *hr_get_ext_state_str(hr_ext_state_t);
    134143extern const char *hr_get_layout_str(hr_layout_t);
     144extern const char *hr_get_level_str(hr_level_t);
    135145extern const char *hr_get_metadata_type_str(hr_metadata_type_t);
    136146
  • uspace/lib/device/include/ipc/hr.h

    r431b513 re0bbecb  
    4646        HR_FAIL_EXTENT,
    4747        HR_ADD_HOTSPARE,
    48         HR_STATUS
     48        HR_GET_VOL_STATES,
     49        HR_GET_VOL_INFO
    4950} hr_request_t;
    5051
  • uspace/lib/device/src/hr.c

    r431b513 re0bbecb  
    209209}
    210210
    211 static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info)
    212 {
    213         errno_t rc;
    214         size_t i;
    215         char *devname;
    216         hr_extent_t *ext;
    217 
    218         printf("--- vol %zu ---\n", index);
    219 
    220         printf("svc_id: %" PRIun "\n", vol_info->svc_id);
    221 
    222         rc = loc_service_get_name(vol_info->svc_id, &devname);
    223         if (rc != EOK)
    224                 return rc;
    225         printf("devname: %s\n", devname);
    226 
    227         printf("state: %s\n", hr_get_vol_state_str(vol_info->state));
    228 
    229         printf("level: %d\n", vol_info->level);
    230         if (vol_info->level == HR_LVL_4 || vol_info->level == HR_LVL_5) {
    231                 printf("layout: %s\n",
    232                     hr_get_layout_str(vol_info->layout));
    233         }
    234         if (vol_info->level == HR_LVL_0 || vol_info->level == HR_LVL_4) {
    235                 if (vol_info->strip_size / 1024 < 1)
    236                         printf("strip size in bytes: %" PRIu32 "\n",
    237                             vol_info->strip_size);
    238                 else
    239                         printf("strip size: %" PRIu32 "K\n",
    240                             vol_info->strip_size / 1024);
    241         }
    242         printf("size in bytes: %" PRIu64 "MiB\n",
    243             vol_info->nblocks * vol_info->bsize / 1024 / 1024);
    244         printf("size in blocks: %" PRIu64 "\n", vol_info->nblocks);
    245         printf("block size: %zu\n", vol_info->bsize);
    246 
    247         if (vol_info->level == HR_LVL_4)
    248                 printf("extents: [P] [state] [index] [devname]\n");
    249         else
    250                 printf("extents: [state] [index] [devname]\n");
    251         for (i = 0; i < vol_info->extent_no; i++) {
    252                 ext = &vol_info->extents[i];
    253                 if (ext->state == HR_EXT_MISSING || ext->state == HR_EXT_NONE) {
    254                         devname = (char *) "MISSING-devname";
    255                 } else {
    256                         rc = loc_service_get_name(ext->svc_id, &devname);
    257                         if (rc != EOK) {
    258                                 printf("loc_service_get_name() failed, skipping...\n");
    259                                 continue;
    260                         }
    261                 }
    262                 if (vol_info->level == HR_LVL_4) {
    263                         if ((i == 0 && vol_info->layout == HR_RLQ_RAID4_0) ||
    264                             (i == vol_info->extent_no - 1 &&
    265                             vol_info->layout == HR_RLQ_RAID4_N))
    266                                 printf("          P   %s    %zu       %s\n", hr_get_ext_state_str(ext->state), i, devname);
    267                         else
    268                                 printf("              %s    %zu       %s\n", hr_get_ext_state_str(ext->state), i, devname);
    269                 } else {
    270                         printf("          %s    %zu       %s\n", hr_get_ext_state_str(ext->state), i, devname);
    271                 }
    272         }
    273 
    274         if (vol_info->hotspare_no == 0)
    275                 return EOK;
    276 
    277         printf("hotspares: [state] [index] [devname]\n");
    278         for (i = 0; i < vol_info->hotspare_no; i++) {
    279                 ext = &vol_info->hotspares[i];
    280                 if (ext->state == HR_EXT_MISSING) {
    281                         devname = (char *) "MISSING-devname";
    282                 } else {
    283                         rc = loc_service_get_name(ext->svc_id, &devname);
    284                         if (rc != EOK)
    285                                 return rc;
    286                 }
    287                 printf("            %s   %zu     %s\n",
    288                     hr_get_ext_state_str(ext->state), i, devname);
    289         }
    290 
    291         return EOK;
    292 }
    293 
    294211/** Stop/deactivate volume.
    295212 *
     
    408325}
    409326
    410 /** Print state of volumes.
    411  *
    412  * @param hr    Server session
    413  *
    414  * @return EOK on success or an error code
    415  */
    416 errno_t hr_print_state(hr_t *hr)
     327/** Get state of volumes.
     328 *
     329 * @param hr            Server session
     330 * @param rpairs        Place to store pointer to (service id, vol state) pairs
     331 * @param rcnt          Place to store pair count
     332 *
     333 * @return EOK on success or an error code
     334 */
     335errno_t hr_get_vol_states(hr_t *hr, hr_pair_vol_state_t **rpairs, size_t *rcnt)
    417336{
    418337        errno_t rc, retval;
    419338        async_exch_t *exch;
    420339        aid_t req;
    421         size_t size, i;
    422         hr_vol_info_t *vols = NULL;
    423 
    424         exch = async_exchange_begin(hr->sess);
    425         if (exch == NULL) {
    426                 rc = EINVAL;
    427                 goto error;
    428         }
    429 
    430         req = async_send_0(exch, HR_STATUS, NULL);
    431         rc = async_data_read_start(exch, &size, sizeof(size_t));
    432         if (rc != EOK) {
    433                 async_exchange_end(exch);
    434                 async_forget(req);
    435                 return rc;
    436         }
    437 
    438         vols = calloc(size, sizeof(hr_vol_info_t));
    439         if (vols == NULL) {
     340        size_t cnt, i;
     341        hr_pair_vol_state_t *pairs = NULL;
     342
     343        exch = async_exchange_begin(hr->sess);
     344        if (exch == NULL) {
     345                rc = EINVAL;
     346                goto error;
     347        }
     348
     349        req = async_send_0(exch, HR_GET_VOL_STATES, NULL);
     350        rc = async_data_read_start(exch, &cnt, sizeof(size_t));
     351        if (rc != EOK) {
     352                async_exchange_end(exch);
     353                async_forget(req);
     354                return rc;
     355        }
     356
     357        pairs = calloc(cnt, sizeof(*pairs));
     358        if (pairs == NULL) {
    440359                async_exchange_end(exch);
    441360                async_forget(req);
     
    443362        }
    444363
    445         for (i = 0; i < size; i++) {
    446                 rc = async_data_read_start(exch, &vols[i],
    447                     sizeof(hr_vol_info_t));
     364        for (i = 0; i < cnt; i++) {
     365                rc = async_data_read_start(exch, &pairs[i], sizeof(*pairs));
    448366                if (rc != EOK) {
    449367                        async_exchange_end(exch);
     
    460378        }
    461379
    462         if (size == 0) {
    463                 printf("no active volumes\n");
    464                 goto error;
    465         }
    466 
    467         for (i = 0; i < size; i++) {
    468                 rc = print_vol_info(i, &vols[i]);
    469                 if (rc != EOK)
    470                         goto error;
    471         }
    472 
    473 error:
    474         if (vols != NULL)
    475                 free(vols);
     380        if (rpairs != NULL)
     381                *rpairs = pairs;
     382        if (rcnt != NULL)
     383                *rcnt = cnt;
     384        return EOK;
     385
     386error:
     387        if (pairs != NULL)
     388                free(pairs);
     389        return rc;
     390}
     391
     392/** Get volume info.
     393 *
     394 * @param hr            Server session
     395 * @param svc_id        Service id of volume
     396 * @param rinfo         Place to store volume info
     397 *
     398 * @return EOK on success or an error code
     399 */
     400errno_t hr_get_vol_info(hr_t *hr, service_id_t svc_id, hr_vol_info_t *rinfo)
     401{
     402        errno_t rc, retval;
     403        async_exch_t *exch;
     404        aid_t req;
     405
     406        exch = async_exchange_begin(hr->sess);
     407        if (exch == NULL) {
     408                rc = EINVAL;
     409                goto error;
     410        }
     411
     412        req = async_send_0(exch, HR_GET_VOL_INFO, NULL);
     413        rc = async_data_write_start(exch, &svc_id, sizeof(svc_id));
     414        if (rc != EOK) {
     415                async_exchange_end(exch);
     416                async_forget(req);
     417                return rc;
     418        }
     419
     420        rc = async_data_read_start(exch, rinfo, sizeof(*rinfo));
     421        async_exchange_end(exch);
     422        if (rc != EOK) {
     423                async_forget(req);
     424                goto error;
     425        }
     426
     427        async_wait_for(req, &retval);
     428        if (retval != EOK) {
     429                rc = retval;
     430                goto error;
     431        }
     432
     433error:
    476434        return rc;
    477435}
     
    555513}
    556514
     515/** Get volume level string.
     516 *
     517 * @param level Levelvalue
     518 *
     519 * @return Level string
     520 */
     521const char *hr_get_level_str(hr_level_t level)
     522{
     523        switch (level) {
     524        case HR_LVL_0:
     525                return "stripe (RAID 0)";
     526        case HR_LVL_1:
     527                return "mirror (RAID 1)";
     528        case HR_LVL_4:
     529                return "dedicated parity (RAID 4)";
     530        case HR_LVL_5:
     531                return "distributed parity (RAID 5)";
     532        default:
     533                return "Invalid RAID level";
     534        }
     535}
     536
    557537/** Get volume metadata type string.
    558538 *
  • uspace/srv/bd/hr/hr.c

    r431b513 re0bbecb  
    5959static void hr_stop_all_srv(ipc_call_t *);
    6060static void hr_add_hotspare_srv(ipc_call_t *);
    61 static void hr_print_state_srv(ipc_call_t *);
     61static void hr_get_vol_states_srv(ipc_call_t *);
    6262static void hr_ctl_conn(ipc_call_t *);
    6363static void hr_client_conn(ipc_call_t *, void *);
     
    416416}
    417417
    418 /** Volume state printing (server).
    419  *
    420  * Prints info about all active volumes.
    421  */
    422 static void hr_print_state_srv(ipc_call_t *icall)
     418/** Send volume states.
     419 *
     420 * Sends the client pairs of (volume service_id, state).
     421 */
     422static void hr_get_vol_states_srv(ipc_call_t *icall)
    423423{
    424424        HR_DEBUG("%s()", __func__);
     
    426426        errno_t rc;
    427427        size_t vol_cnt = 0;
    428         hr_vol_info_t info;
     428        hr_pair_vol_state_t pair;
    429429        ipc_call_t call;
    430430        size_t size;
     
    439439        }
    440440
    441         if (size != sizeof(size_t)) {
     441        if (size != sizeof(vol_cnt)) {
    442442                rc = EINVAL;
    443443                goto error;
     
    449449
    450450        list_foreach(hr_volumes, lvolumes, hr_volume_t, vol) {
    451                 memcpy(info.extents, vol->extents,
    452                     sizeof(hr_extent_t) * HR_MAX_EXTENTS);
    453                 memcpy(info.hotspares, vol->hotspares,
    454                     sizeof(hr_extent_t) * HR_MAX_HOTSPARES);
    455                 info.svc_id = vol->svc_id;
    456                 info.extent_no = vol->extent_no;
    457                 info.hotspare_no = vol->hotspare_no;
    458                 info.level = vol->level;
    459                 /* print usable number of blocks */
    460                 /* TODO: change to data_blkno */
    461                 info.nblocks = vol->data_blkno;
    462                 info.strip_size = vol->strip_size;
    463                 info.bsize = vol->bsize;
    464                 info.state = vol->state;
    465                 info.layout = vol->layout;
     451                pair.svc_id = vol->svc_id;
     452                pair.state = vol->state;
    466453
    467454                if (!async_data_read_receive(&call, &size)) {
     
    470457                }
    471458
    472                 if (size != sizeof(hr_vol_info_t)) {
     459                if (size != sizeof(pair)) {
    473460                        rc = EINVAL;
    474461                        goto error;
    475462                }
    476463
    477                 rc = async_data_read_finalize(&call, &info, size);
     464                rc = async_data_read_finalize(&call, &pair, size);
    478465                if (rc != EOK)
    479466                        goto error;
     
    489476}
    490477
     478/** Send volume info.
     479 *
     480 * Sends the client volume info.
     481 */
     482static void hr_get_vol_info_srv(ipc_call_t *icall)
     483{
     484        HR_DEBUG("%s()", __func__);
     485
     486        errno_t rc;
     487        size_t size;
     488        ipc_call_t call;
     489        service_id_t svc_id;
     490        hr_vol_info_t info;
     491        hr_volume_t *vol;
     492
     493        if (!async_data_write_receive(&call, &size)) {
     494                rc = EREFUSED;
     495                goto error;
     496        }
     497
     498        if (size != sizeof(service_id_t)) {
     499                rc = EINVAL;
     500                goto error;
     501        }
     502
     503        rc = async_data_write_finalize(&call, &svc_id, size);
     504        if (rc != EOK)
     505                goto error;
     506
     507        vol = hr_get_volume(svc_id);
     508        if (vol == NULL) {
     509                rc = ENOENT;
     510                goto error;
     511        }
     512
     513        memcpy(info.extents, vol->extents,
     514            sizeof(hr_extent_t) * HR_MAX_EXTENTS);
     515        memcpy(info.hotspares, vol->hotspares,
     516            sizeof(hr_extent_t) * HR_MAX_HOTSPARES);
     517        info.svc_id = vol->svc_id;
     518        info.extent_no = vol->extent_no;
     519        info.hotspare_no = vol->hotspare_no;
     520        info.level = vol->level;
     521        info.data_blkno = vol->data_blkno;
     522        info.strip_size = vol->strip_size;
     523        info.bsize = vol->bsize;
     524        info.state = vol->state;
     525        info.layout = vol->layout;
     526        info.meta_type = vol->meta_ops->get_type();
     527        memcpy(info.devname, vol->devname, HR_DEVNAME_LEN);
     528
     529        if (!async_data_read_receive(&call, &size)) {
     530                rc = EREFUSED;
     531                goto error;
     532        }
     533
     534        if (size != sizeof(info)) {
     535                rc = EINVAL;
     536                goto error;
     537        }
     538
     539        rc = async_data_read_finalize(&call, &info, size);
     540        if (rc != EOK)
     541                goto error;
     542
     543        async_answer_0(icall, EOK);
     544        return;
     545error:
     546        async_answer_0(&call, rc);
     547        async_answer_0(icall, rc);
     548}
     549
    491550/**  HelenRAID server control IPC methods crossroad.
    492551 */
     
    529588                        hr_add_hotspare_srv(&call);
    530589                        break;
    531                 case HR_STATUS:
    532                         hr_print_state_srv(&call);
     590                case HR_GET_VOL_STATES:
     591                        hr_get_vol_states_srv(&call);
     592                        break;
     593                case HR_GET_VOL_INFO:
     594                        hr_get_vol_info_srv(&call);
    533595                        break;
    534596                default:
Note: See TracChangeset for help on using the changeset viewer.