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

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

hr: rename hr_get_*_status_msg → hr_get_*_state_str

  • Property mode set to 100644
File size: 12.4 KB
Line 
1/*
2 * Copyright (c) 2025 Miroslav Cimerman
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/**
33 * @file HelenRAID client API
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
46/** Initialize server session.
47 *
48 * @param rhr Place to store inited session
49 *
50 * @return EOK on success or an error code
51 */
52errno_t hr_sess_init(hr_t **rhr)
53{
54 errno_t rc;
55 hr_t *hr = NULL;
56
57 if (rhr == NULL)
58 return EINVAL;
59
60 hr = calloc(1, sizeof(hr_t));
61 if (hr == NULL) {
62 rc = ENOMEM;
63 goto error;
64 }
65
66 service_id_t hr_svcid;
67
68 rc = loc_service_get_id(SERVICE_NAME_HR, &hr_svcid, 0);
69 if (rc != EOK)
70 goto error;
71
72 hr->sess = loc_service_connect(hr_svcid, INTERFACE_HR, 0);
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);
83
84 return rc;
85}
86
87/** Destroy server session.
88 *
89 * @param hr Session to destroy
90 */
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
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 */
107errno_t hr_create(hr_t *hr, hr_config_t *hr_config)
108{
109 errno_t rc, retval;
110 async_exch_t *exch;
111 aid_t req;
112
113 exch = async_exchange_begin(hr->sess);
114 if (exch == NULL)
115 return EINVAL;
116
117 req = async_send_0(exch, HR_CREATE, NULL);
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);
128 return retval;
129}
130
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 */
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
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 */
182errno_t hr_auto_assemble(hr_t *hr, size_t *rassembled_cnt)
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
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;
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("status: %s\n", hr_get_vol_state_str(vol_info->status));
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] [status] [index] [devname]\n");
249 else
250 printf("extents: [status] [index] [devname]\n");
251 for (i = 0; i < vol_info->extent_no; i++) {
252 ext = &vol_info->extents[i];
253 if (ext->status == HR_EXT_MISSING || ext->status == 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->status), i, devname);
267 else
268 printf(" %s %zu %s\n", hr_get_ext_state_str(ext->status), i, devname);
269 } else {
270 printf(" %s %zu %s\n", hr_get_ext_state_str(ext->status), i, devname);
271 }
272 }
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",
288 hr_get_ext_state_str(ext->status), i, devname);
289 }
290
291 return EOK;
292}
293
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 */
301errno_t hr_stop(hr_t *hr, const char *devname)
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 }
316
317 rc = async_req_1_0(exch, HR_STOP, svc_id);
318 async_exchange_end(exch);
319error:
320 return rc;
321}
322
323/** Stop/deactivate all volumes.
324 *
325 * @param hr Server session
326 *
327 * @return EOK on success or an error code
328 */
329errno_t hr_stop_all(hr_t *hr)
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
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 */
354errno_t hr_fail_extent(hr_t *hr, const char *volume_name, unsigned long extent)
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);
371 async_exchange_end(exch);
372error:
373 return rc;
374}
375
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 */
384errno_t hr_add_hotspare(hr_t *hr, const char *volume_name, const char *hotspare)
385{
386 errno_t rc;
387 async_exch_t *exch;
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;
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
410/** Print state of volumes.
411 *
412 * @param hr Server session
413 *
414 * @return EOK on success or an error code
415 */
416errno_t hr_print_status(hr_t *hr)
417{
418 errno_t rc, retval;
419 async_exch_t *exch;
420 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) {
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
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
473error:
474 if (vols != NULL)
475 free(vols);
476 return rc;
477}
478
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)
486{
487 switch (status) {
488 case HR_VOL_NONE:
489 return "NONE/UNKNOWN";
490 case HR_VOL_ONLINE:
491 return "ONLINE";
492 case HR_VOL_FAULTY:
493 return "FAULTY";
494 case HR_VOL_DEGRADED:
495 return "DEGRADED";
496 case HR_VOL_REBUILD:
497 return "REBUILD";
498 default:
499 return "Invalid state value";
500 }
501}
502
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)
510{
511 switch (status) {
512 case HR_EXT_NONE:
513 return "NONE/UNKNOWN";
514 case HR_EXT_INVALID:
515 return "INVALID";
516 case HR_EXT_ONLINE:
517 return "ONLINE";
518 case HR_EXT_MISSING:
519 return "MISSING";
520 case HR_EXT_FAILED:
521 return "FAILED";
522 case HR_EXT_REBUILD:
523 return "REBUILD";
524 case HR_EXT_HOTSPARE:
525 return "HOTSPARE";
526 default:
527 return "Invalid state value";
528 }
529}
530
531/** Get volume layout string.
532 *
533 * @param layout Layout value
534 *
535 * @return Layout string
536 */
537const char *hr_get_layout_str(hr_layout_t layout)
538{
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";
552 default:
553 return "Invalid RAID layout";
554 }
555}
556
557/** Get volume metadata type string.
558 *
559 * @param type Metadata type value
560 *
561 * @return Metadata type string
562 */
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
577/** @}
578 */
Note: See TracBrowser for help on using the repository browser.