source: mainline/uspace/lib/device/src/hr.c@ 155d34f

Last change on this file since 155d34f was 155d34f, checked in by Miroslav Cimerman <mc@…>, 8 weeks ago

hr: rename hr_get_*_status_msg → hr_get_*_state_str

  • Property mode set to 100644
File size: 12.4 KB
RevLine 
[94d84a0]1/*
[d082801]2 * Copyright (c) 2025 Miroslav Cimerman
[94d84a0]3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libdevice
30 * @{
31 */
32/**
[af4ecb76]33 * @file HelenRAID client API
[94d84a0]34 */
35
36#include <abi/ipc/interfaces.h>
37#include <async.h>
38#include <hr.h>
39#include <ipc/hr.h>
40#include <ipc/services.h>
41#include <loc.h>
42#include <stdlib.h>
43#include <stdio.h>
44#include <str.h>
45
[af4ecb76]46/** Initialize server session.
47 *
48 * @param rhr Place to store inited session
49 *
50 * @return EOK on success or an error code
51 */
[94d84a0]52errno_t hr_sess_init(hr_t **rhr)
53{
54 errno_t rc;
[40be7eb]55 hr_t *hr = NULL;
[94d84a0]56
[40be7eb]57 if (rhr == NULL)
58 return EINVAL;
59
60 hr = calloc(1, sizeof(hr_t));
[94d84a0]61 if (hr == NULL) {
62 rc = ENOMEM;
63 goto error;
64 }
65
66 service_id_t hr_svcid;
67
[6784abc]68 rc = loc_service_get_id(SERVICE_NAME_HR, &hr_svcid, 0);
[40be7eb]69 if (rc != EOK)
[94d84a0]70 goto error;
71
[6784abc]72 hr->sess = loc_service_connect(hr_svcid, INTERFACE_HR, 0);
[94d84a0]73 if (hr->sess == NULL) {
74 rc = EIO;
75 goto error;
76 }
77
78 *rhr = hr;
79 return EOK;
80error:
81 if (hr != NULL)
82 free(hr);
[40be7eb]83
[94d84a0]84 return rc;
85}
86
[af4ecb76]87/** Destroy server session.
88 *
89 * @param hr Session to destroy
90 */
[94d84a0]91void hr_sess_destroy(hr_t *hr)
92{
93 if (hr == NULL)
94 return;
95
96 async_hangup(hr->sess);
97 free(hr);
98}
99
[af4ecb76]100/** Create volume.
101 *
102 * @param hr Server session
103 * @param hr_config Config to create from
104 *
105 * @return EOK on success or an error code
106 */
[d082801]107errno_t hr_create(hr_t *hr, hr_config_t *hr_config)
[94d84a0]108{
109 errno_t rc, retval;
110 async_exch_t *exch;
111 aid_t req;
112
113 exch = async_exchange_begin(hr->sess);
[68e357e]114 if (exch == NULL)
[94d84a0]115 return EINVAL;
116
[d082801]117 req = async_send_0(exch, HR_CREATE, NULL);
[b0f1366]118
119 rc = async_data_write_start(exch, hr_config, sizeof(hr_config_t));
120 if (rc != EOK) {
121 async_exchange_end(exch);
122 async_forget(req);
123 return rc;
124 }
125
126 async_exchange_end(exch);
127 async_wait_for(req, &retval);
[d1d355f]128 return retval;
[b0f1366]129}
130
[af4ecb76]131/** Assemble volumes.
132 *
133 * @param hr Server session
134 * @param hr_config Config to assemble from
135 * @param rassembled_cnt Place to store assembled count
136 *
137 * @return EOK on success or an error code
138 */
[d082801]139errno_t hr_assemble(hr_t *hr, hr_config_t *hr_config, size_t *rassembled_cnt)
140{
141 errno_t rc;
142 async_exch_t *exch;
143 aid_t req;
144 size_t assembled_cnt;
145
146 exch = async_exchange_begin(hr->sess);
147 if (exch == NULL)
148 return EINVAL;
149
150 req = async_send_0(exch, HR_ASSEMBLE, NULL);
151
152 rc = async_data_write_start(exch, hr_config, sizeof(hr_config_t));
153 if (rc != EOK) {
154 async_exchange_end(exch);
155 async_forget(req);
156 return rc;
157 }
158
159 rc = async_data_read_start(exch, &assembled_cnt, sizeof(size_t));
160 if (rc != EOK) {
161 async_exchange_end(exch);
162 async_forget(req);
163 return rc;
164 }
165
166 async_exchange_end(exch);
167 async_wait_for(req, &rc);
168
169 if (rassembled_cnt != NULL)
170 *rassembled_cnt = assembled_cnt;
171
172 return rc;
173}
174
[af4ecb76]175/** Automatically assemble volumes.
176 *
177 * @param hr Server session
178 * @param rassembled_cnt Place to store assembled count
179 *
180 * @return EOK on success or an error code
181 */
[fc265b4]182errno_t hr_auto_assemble(hr_t *hr, size_t *rassembled_cnt)
[8b51009]183{
184 errno_t rc;
185 size_t assembled_cnt;
186
187 async_exch_t *exch = async_exchange_begin(hr->sess);
188 if (exch == NULL) {
189 rc = EINVAL;
190 goto error;
191 }
192
193 aid_t req = async_send_0(exch, HR_AUTO_ASSEMBLE, NULL);
194
195 rc = async_data_read_start(exch, &assembled_cnt, sizeof(size_t));
196 if (rc != EOK) {
197 async_exchange_end(exch);
198 async_forget(req);
199 return rc;
200 }
201
202 async_exchange_end(exch);
203 async_wait_for(req, &rc);
204
205 if (rassembled_cnt != NULL)
206 *rassembled_cnt = assembled_cnt;
207error:
208 return rc;
209}
210
[095a989]211static 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;
[dbd91da]216 hr_extent_t *ext;
[095a989]217
218 printf("--- vol %zu ---\n", index);
219
[ca7fa5b]220 printf("svc_id: %" PRIun "\n", vol_info->svc_id);
[095a989]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
[155d34f]227 printf("status: %s\n", hr_get_vol_state_str(vol_info->status));
[e47a032]228
[095a989]229 printf("level: %d\n", vol_info->level);
[4066371]230 if (vol_info->level == HR_LVL_4 || vol_info->level == HR_LVL_5) {
231 printf("layout: %s\n",
[fb06476f]232 hr_get_layout_str(vol_info->layout));
[4066371]233 }
[50bed55d]234 if (vol_info->level == HR_LVL_0 || vol_info->level == HR_LVL_4) {
[9c1cf34c]235 if (vol_info->strip_size / 1024 < 1)
[ca7fa5b]236 printf("strip size in bytes: %" PRIu32 "\n",
[9c1cf34c]237 vol_info->strip_size);
238 else
[ca7fa5b]239 printf("strip size: %" PRIu32 "K\n",
[9c1cf34c]240 vol_info->strip_size / 1024);
241 }
[ca7fa5b]242 printf("size in bytes: %" PRIu64 "MiB\n",
[9c1cf34c]243 vol_info->nblocks * vol_info->bsize / 1024 / 1024);
[ca7fa5b]244 printf("size in blocks: %" PRIu64 "\n", vol_info->nblocks);
[9c1cf34c]245 printf("block size: %zu\n", vol_info->bsize);
246
[50bed55d]247 if (vol_info->level == HR_LVL_4)
[dbd91da]248 printf("extents: [P] [status] [index] [devname]\n");
249 else
250 printf("extents: [status] [index] [devname]\n");
[095a989]251 for (i = 0; i < vol_info->extent_no; i++) {
[dbd91da]252 ext = &vol_info->extents[i];
[4200735]253 if (ext->status == HR_EXT_MISSING || ext->status == HR_EXT_NONE) {
[e47a032]254 devname = (char *) "MISSING-devname";
255 } else {
256 rc = loc_service_get_name(ext->svc_id, &devname);
[4200735]257 if (rc != EOK) {
258 printf("loc_service_get_name() failed, skipping...\n");
259 continue;
260 }
[e47a032]261 }
[4066371]262 if (vol_info->level == HR_LVL_4) {
[37a9c1e]263 if ((i == 0 && vol_info->layout == HR_RLQ_RAID4_0) ||
[4066371]264 (i == vol_info->extent_no - 1 &&
[37a9c1e]265 vol_info->layout == HR_RLQ_RAID4_N))
[155d34f]266 printf(" P %s %zu %s\n", hr_get_ext_state_str(ext->status), i, devname);
[4066371]267 else
[155d34f]268 printf(" %s %zu %s\n", hr_get_ext_state_str(ext->status), i, devname);
[4066371]269 } else {
[155d34f]270 printf(" %s %zu %s\n", hr_get_ext_state_str(ext->status), i, devname);
[4066371]271 }
[095a989]272 }
[5b320ac]273
274 if (vol_info->hotspare_no == 0)
275 return EOK;
276
277 printf("hotspares: [status] [index] [devname]\n");
278 for (i = 0; i < vol_info->hotspare_no; i++) {
279 ext = &vol_info->hotspares[i];
280 if (ext->status == 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",
[155d34f]288 hr_get_ext_state_str(ext->status), i, devname);
[5b320ac]289 }
290
[095a989]291 return EOK;
292}
293
[af4ecb76]294/** Stop/deactivate volume.
295 *
296 * @param hr Server session
297 * @param devname Volume name
298 *
299 * @return EOK on success or an error code
300 */
[fc265b4]301errno_t hr_stop(hr_t *hr, const char *devname)
[a19d7fc4]302{
303 errno_t rc;
304 async_exch_t *exch;
305 service_id_t svc_id;
306
307 rc = loc_service_get_id(devname, &svc_id, 0);
308 if (rc != EOK)
309 return rc;
310
311 exch = async_exchange_begin(hr->sess);
312 if (exch == NULL) {
313 rc = EINVAL;
314 goto error;
315 }
[d1d355f]316
317 rc = async_req_1_0(exch, HR_STOP, svc_id);
318 async_exchange_end(exch);
319error:
320 return rc;
321}
322
[af4ecb76]323/** Stop/deactivate all volumes.
324 *
325 * @param hr Server session
326 *
327 * @return EOK on success or an error code
328 */
[fc265b4]329errno_t hr_stop_all(hr_t *hr)
[d1d355f]330{
331 async_exch_t *exch;
332 errno_t rc;
333
334 exch = async_exchange_begin(hr->sess);
335 if (exch == NULL) {
336 rc = EINVAL;
337 goto error;
338 }
339
340 rc = async_req_0_0(exch, HR_STOP_ALL);
341 async_exchange_end(exch);
342error:
343 return rc;
344}
345
[af4ecb76]346/** Fail an extent in volume.
347 *
348 * @param hr Server session
349 * @param volume_name Volume name
350 * @param extent Extent index to fail
351 *
352 * @return EOK on success or an error code
353 */
[fc265b4]354errno_t hr_fail_extent(hr_t *hr, const char *volume_name, unsigned long extent)
[d1d355f]355{
356 errno_t rc;
357 async_exch_t *exch;
358 service_id_t vol_svc_id;
359
360 rc = loc_service_get_id(volume_name, &vol_svc_id, 0);
361 if (rc != EOK)
362 return rc;
363
364 exch = async_exchange_begin(hr->sess);
365 if (exch == NULL) {
366 rc = EINVAL;
367 goto error;
368 }
369
370 rc = async_req_2_0(exch, HR_FAIL_EXTENT, vol_svc_id, extent);
[a19d7fc4]371 async_exchange_end(exch);
372error:
373 return rc;
374}
375
[af4ecb76]376/** Add a hotspare to volume.
377 *
378 * @param hr Server session
379 * @param volume_name Volume name
380 * @param hotspare Hotspare service name
381 *
382 * @return EOK on success or an error code
383 */
[fc265b4]384errno_t hr_add_hotspare(hr_t *hr, const char *volume_name, const char *hotspare)
[5b320ac]385{
386 errno_t rc;
387 async_exch_t *exch;
[d1d355f]388 service_id_t vol_svc_id, hs_svc_id;
389
390 rc = loc_service_get_id(volume_name, &vol_svc_id, 0);
391 if (rc != EOK)
392 return rc;
393
394 rc = loc_service_get_id(hotspare, &hs_svc_id, 0);
395 if (rc != EOK)
396 return rc;
[5b320ac]397
398 exch = async_exchange_begin(hr->sess);
399 if (exch == NULL) {
400 rc = EINVAL;
401 goto error;
402 }
403
404 rc = async_req_2_0(exch, HR_ADD_HOTSPARE, vol_svc_id, hs_svc_id);
405 async_exchange_end(exch);
406error:
407 return rc;
408}
409
[af4ecb76]410/** Print state of volumes.
411 *
412 * @param hr Server session
413 *
414 * @return EOK on success or an error code
415 */
[fc265b4]416errno_t hr_print_status(hr_t *hr)
[095a989]417{
418 errno_t rc, retval;
419 async_exch_t *exch;
420 aid_t req;
421 size_t size, i;
[a19d7fc4]422 hr_vol_info_t *vols = NULL;
[095a989]423
424 exch = async_exchange_begin(hr->sess);
[a19d7fc4]425 if (exch == NULL) {
426 rc = EINVAL;
427 goto error;
428 }
[095a989]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) {
440 async_exchange_end(exch);
441 async_forget(req);
442 return ENOMEM;
443 }
444
445 for (i = 0; i < size; i++) {
446 rc = async_data_read_start(exch, &vols[i],
447 sizeof(hr_vol_info_t));
448 if (rc != EOK) {
449 async_exchange_end(exch);
450 async_forget(req);
451 goto error;
452 }
453 }
454
455 async_exchange_end(exch);
456 async_wait_for(req, &retval);
457 if (retval != EOK) {
458 rc = retval;
459 goto error;
460 }
461
[a19d7fc4]462 if (size == 0) {
[fc265b4]463 printf("no active volumes\n");
[a19d7fc4]464 goto error;
465 }
466
[095a989]467 for (i = 0; i < size; i++) {
468 rc = print_vol_info(i, &vols[i]);
469 if (rc != EOK)
470 goto error;
471 }
472
473error:
474 if (vols != NULL)
475 free(vols);
476 return rc;
477}
478
[155d34f]479/** Get volume state string.
480 *
481 * @param state State value
482 *
483 * @return State string
484 */
485const char *hr_get_vol_state_str(hr_vol_status_t status)
[e47a032]486{
487 switch (status) {
[e24c064]488 case HR_VOL_NONE:
489 return "NONE/UNKNOWN";
[e47a032]490 case HR_VOL_ONLINE:
491 return "ONLINE";
492 case HR_VOL_FAULTY:
493 return "FAULTY";
[13ce552]494 case HR_VOL_DEGRADED:
495 return "DEGRADED";
[5b320ac]496 case HR_VOL_REBUILD:
497 return "REBUILD";
[e47a032]498 default:
[e24c064]499 return "Invalid state value";
[e47a032]500 }
501}
502
[155d34f]503/** Get extent state string.
504 *
505 * @param state State value
506 *
507 * @return State string
508 */
509const char *hr_get_ext_state_str(hr_ext_status_t status)
[e47a032]510{
511 switch (status) {
[e24c064]512 case HR_EXT_NONE:
513 return "NONE/UNKNOWN";
[3a68baa]514 case HR_EXT_INVALID:
515 return "INVALID";
[e47a032]516 case HR_EXT_ONLINE:
517 return "ONLINE";
518 case HR_EXT_MISSING:
519 return "MISSING";
520 case HR_EXT_FAILED:
521 return "FAILED";
[5b320ac]522 case HR_EXT_REBUILD:
523 return "REBUILD";
524 case HR_EXT_HOTSPARE:
525 return "HOTSPARE";
[e47a032]526 default:
[e24c064]527 return "Invalid state value";
[e47a032]528 }
529}
530
[155d34f]531/** Get volume layout string.
532 *
533 * @param layout Layout value
534 *
535 * @return Layout string
536 */
[fb06476f]537const char *hr_get_layout_str(hr_layout_t layout)
[4066371]538{
[fb06476f]539 switch (layout) {
540 case HR_RLQ_NONE:
541 return "RAID layout not set";
542 case HR_RLQ_RAID4_0:
543 return "RAID-4 Non-Rotating Parity 0";
544 case HR_RLQ_RAID4_N:
545 return "RAID-4 Non-Rotating Parity N";
546 case HR_RLQ_RAID5_0R:
547 return "RAID-5 Rotating Parity 0 with Data Restart";
548 case HR_RLQ_RAID5_NR:
549 return "RAID-5 Rotating Parity N with Data Restart";
550 case HR_RLQ_RAID5_NC:
551 return "RAID-5 Rotating Parity N with Data Continuation";
[4066371]552 default:
[fb06476f]553 return "Invalid RAID layout";
[4066371]554 }
555}
556
[155d34f]557/** Get volume metadata type string.
558 *
559 * @param type Metadata type value
560 *
561 * @return Metadata type string
562 */
[b883aa8]563const char *hr_get_metadata_type_str(hr_metadata_type_t type)
564{
565 switch (type) {
566 case HR_METADATA_NATIVE:
567 return "Native HelenRAID metadata";
568 case HR_METADATA_GEOM_MIRROR:
569 return "GEOM::MIRROR";
570 case HR_METADATA_GEOM_STRIPE:
571 return "GEOM::STRIPE";
572 default:
573 return "Invalid metadata type value";
574 }
575}
576
[94d84a0]577/** @}
578 */
Note: See TracBrowser for help on using the repository browser.