source: mainline/uspace/lib/device/src/hr.c@ 31eb568

Last change on this file since 31eb568 was d1d355f, checked in by Miroslav Cimerman <mc@…>, 8 months ago

hr: refactor hrctl and some hr IPC methods

  • Property mode set to 100644
File size: 11.1 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
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
46errno_t hr_sess_init(hr_t **rhr)
47{
48 errno_t rc;
49 hr_t *hr = NULL;
50
51 if (rhr == NULL)
52 return EINVAL;
53
54 hr = calloc(1, sizeof(hr_t));
55 if (hr == NULL) {
56 rc = ENOMEM;
57 goto error;
58 }
59
60 service_id_t hr_svcid;
61
62 rc = loc_service_get_id(SERVICE_NAME_HR, &hr_svcid, 0);
63 if (rc != EOK)
64 goto error;
65
66 hr->sess = loc_service_connect(hr_svcid, INTERFACE_HR, 0);
67 if (hr->sess == NULL) {
68 rc = EIO;
69 goto error;
70 }
71
72 *rhr = hr;
73 return EOK;
74error:
75 if (hr != NULL)
76 free(hr);
77
78 return rc;
79}
80
81void hr_sess_destroy(hr_t *hr)
82{
83 if (hr == NULL)
84 return;
85
86 async_hangup(hr->sess);
87 free(hr);
88}
89
90errno_t hr_create(hr_t *hr, hr_config_t *hr_config)
91{
92 errno_t rc, retval;
93 async_exch_t *exch;
94 aid_t req;
95
96 exch = async_exchange_begin(hr->sess);
97 if (exch == NULL)
98 return EINVAL;
99
100 req = async_send_0(exch, HR_CREATE, NULL);
101
102 rc = async_data_write_start(exch, hr_config, sizeof(hr_config_t));
103 if (rc != EOK) {
104 async_exchange_end(exch);
105 async_forget(req);
106 return rc;
107 }
108
109 async_exchange_end(exch);
110 async_wait_for(req, &retval);
111 return retval;
112}
113
114errno_t hr_assemble(hr_t *hr, hr_config_t *hr_config, size_t *rassembled_cnt)
115{
116 errno_t rc;
117 async_exch_t *exch;
118 aid_t req;
119 size_t assembled_cnt;
120
121 exch = async_exchange_begin(hr->sess);
122 if (exch == NULL)
123 return EINVAL;
124
125 req = async_send_0(exch, HR_ASSEMBLE, NULL);
126
127 rc = async_data_write_start(exch, hr_config, sizeof(hr_config_t));
128 if (rc != EOK) {
129 async_exchange_end(exch);
130 async_forget(req);
131 return rc;
132 }
133
134 rc = async_data_read_start(exch, &assembled_cnt, sizeof(size_t));
135 if (rc != EOK) {
136 async_exchange_end(exch);
137 async_forget(req);
138 return rc;
139 }
140
141 async_exchange_end(exch);
142 async_wait_for(req, &rc);
143
144 if (rassembled_cnt != NULL)
145 *rassembled_cnt = assembled_cnt;
146
147 return rc;
148}
149
150errno_t hr_auto_assemble(size_t *rassembled_cnt)
151{
152 hr_t *hr;
153 errno_t rc;
154 size_t assembled_cnt;
155
156 rc = hr_sess_init(&hr);
157 if (rc != EOK)
158 return rc;
159
160 async_exch_t *exch = async_exchange_begin(hr->sess);
161 if (exch == NULL) {
162 rc = EINVAL;
163 goto error;
164 }
165
166 aid_t req = async_send_0(exch, HR_AUTO_ASSEMBLE, NULL);
167
168 rc = async_data_read_start(exch, &assembled_cnt, sizeof(size_t));
169 if (rc != EOK) {
170 async_exchange_end(exch);
171 async_forget(req);
172 return rc;
173 }
174
175 async_exchange_end(exch);
176 async_wait_for(req, &rc);
177
178 if (rassembled_cnt != NULL)
179 *rassembled_cnt = assembled_cnt;
180error:
181 hr_sess_destroy(hr);
182 return rc;
183}
184
185static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info)
186{
187 errno_t rc;
188 size_t i;
189 char *devname;
190 hr_extent_t *ext;
191
192 printf("--- vol %zu ---\n", index);
193
194 printf("svc_id: %" PRIun "\n", vol_info->svc_id);
195
196 rc = loc_service_get_name(vol_info->svc_id, &devname);
197 if (rc != EOK)
198 return rc;
199 printf("devname: %s\n", devname);
200
201 printf("status: %s\n", hr_get_vol_status_msg(vol_info->status));
202
203 printf("level: %d\n", vol_info->level);
204 if (vol_info->level == HR_LVL_4 || vol_info->level == HR_LVL_5) {
205 printf("layout: %s\n",
206 hr_get_layout_str(vol_info->layout));
207 }
208 if (vol_info->level == HR_LVL_0 || vol_info->level == HR_LVL_4) {
209 if (vol_info->strip_size / 1024 < 1)
210 printf("strip size in bytes: %" PRIu32 "\n",
211 vol_info->strip_size);
212 else
213 printf("strip size: %" PRIu32 "K\n",
214 vol_info->strip_size / 1024);
215 }
216 printf("size in bytes: %" PRIu64 "MiB\n",
217 vol_info->nblocks * vol_info->bsize / 1024 / 1024);
218 printf("size in blocks: %" PRIu64 "\n", vol_info->nblocks);
219 printf("block size: %zu\n", vol_info->bsize);
220
221 if (vol_info->level == HR_LVL_4)
222 printf("extents: [P] [status] [index] [devname]\n");
223 else
224 printf("extents: [status] [index] [devname]\n");
225 for (i = 0; i < vol_info->extent_no; i++) {
226 ext = &vol_info->extents[i];
227 if (ext->status == HR_EXT_MISSING || ext->status == HR_EXT_NONE) {
228 devname = (char *) "MISSING-devname";
229 } else {
230 rc = loc_service_get_name(ext->svc_id, &devname);
231 if (rc != EOK) {
232 printf("loc_service_get_name() failed, skipping...\n");
233 continue;
234 }
235 }
236 if (vol_info->level == HR_LVL_4) {
237 if ((i == 0 && vol_info->layout == HR_RLQ_RAID4_0) ||
238 (i == vol_info->extent_no - 1 &&
239 vol_info->layout == HR_RLQ_RAID4_N))
240 printf(" P %s %zu %s\n", hr_get_ext_status_msg(ext->status), i, devname);
241 else
242 printf(" %s %zu %s\n", hr_get_ext_status_msg(ext->status), i, devname);
243 } else {
244 printf(" %s %zu %s\n", hr_get_ext_status_msg(ext->status), i, devname);
245 }
246 }
247
248 if (vol_info->hotspare_no == 0)
249 return EOK;
250
251 printf("hotspares: [status] [index] [devname]\n");
252 for (i = 0; i < vol_info->hotspare_no; i++) {
253 ext = &vol_info->hotspares[i];
254 if (ext->status == HR_EXT_MISSING) {
255 devname = (char *) "MISSING-devname";
256 } else {
257 rc = loc_service_get_name(ext->svc_id, &devname);
258 if (rc != EOK)
259 return rc;
260 }
261 printf(" %s %zu %s\n",
262 hr_get_ext_status_msg(ext->status), i, devname);
263 }
264
265 return EOK;
266}
267
268errno_t hr_stop(const char *devname)
269{
270 hr_t *hr;
271 errno_t rc;
272 async_exch_t *exch;
273 service_id_t svc_id;
274
275 rc = loc_service_get_id(devname, &svc_id, 0);
276 if (rc != EOK)
277 return rc;
278
279 rc = hr_sess_init(&hr);
280 if (rc != EOK)
281 return rc;
282
283 exch = async_exchange_begin(hr->sess);
284 if (exch == NULL) {
285 rc = EINVAL;
286 goto error;
287 }
288
289 rc = async_req_1_0(exch, HR_STOP, svc_id);
290 async_exchange_end(exch);
291error:
292 hr_sess_destroy(hr);
293 return rc;
294}
295
296errno_t hr_stop_all(void)
297{
298 hr_t *hr;
299 async_exch_t *exch;
300 errno_t rc;
301
302 rc = hr_sess_init(&hr);
303 if (rc != EOK)
304 return rc;
305
306 exch = async_exchange_begin(hr->sess);
307 if (exch == NULL) {
308 rc = EINVAL;
309 goto error;
310 }
311
312 rc = async_req_0_0(exch, HR_STOP_ALL);
313 async_exchange_end(exch);
314error:
315 hr_sess_destroy(hr);
316 return rc;
317}
318
319errno_t hr_fail_extent(const char *volume_name, unsigned long extent)
320{
321 hr_t *hr;
322 errno_t rc;
323 async_exch_t *exch;
324 service_id_t vol_svc_id;
325
326 rc = loc_service_get_id(volume_name, &vol_svc_id, 0);
327 if (rc != EOK)
328 return rc;
329
330 rc = hr_sess_init(&hr);
331 if (rc != EOK)
332 return 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_2_0(exch, HR_FAIL_EXTENT, vol_svc_id, extent);
341 async_exchange_end(exch);
342error:
343 hr_sess_destroy(hr);
344 return rc;
345}
346
347errno_t hr_add_hotspare(const char *volume_name, const char *hotspare)
348{
349 hr_t *hr;
350 errno_t rc;
351 async_exch_t *exch;
352 service_id_t vol_svc_id, hs_svc_id;
353
354 rc = loc_service_get_id(volume_name, &vol_svc_id, 0);
355 if (rc != EOK)
356 return rc;
357
358 rc = loc_service_get_id(hotspare, &hs_svc_id, 0);
359 if (rc != EOK)
360 return rc;
361
362 rc = hr_sess_init(&hr);
363 if (rc != EOK)
364 return rc;
365
366 exch = async_exchange_begin(hr->sess);
367 if (exch == NULL) {
368 rc = EINVAL;
369 goto error;
370 }
371
372 rc = async_req_2_0(exch, HR_ADD_HOTSPARE, vol_svc_id, hs_svc_id);
373 async_exchange_end(exch);
374error:
375 hr_sess_destroy(hr);
376 return rc;
377}
378
379errno_t hr_print_status(void)
380{
381 hr_t *hr;
382 errno_t rc, retval;
383 async_exch_t *exch;
384 aid_t req;
385 size_t size, i;
386 hr_vol_info_t *vols = NULL;
387
388 rc = hr_sess_init(&hr);
389 if (rc != EOK)
390 return rc;
391
392 exch = async_exchange_begin(hr->sess);
393 if (exch == NULL) {
394 rc = EINVAL;
395 goto error;
396 }
397
398 req = async_send_0(exch, HR_STATUS, NULL);
399 rc = async_data_read_start(exch, &size, sizeof(size_t));
400 if (rc != EOK) {
401 async_exchange_end(exch);
402 async_forget(req);
403 return rc;
404 }
405
406 vols = calloc(size, sizeof(hr_vol_info_t));
407 if (vols == NULL) {
408 async_exchange_end(exch);
409 async_forget(req);
410 return ENOMEM;
411 }
412
413 for (i = 0; i < size; i++) {
414 rc = async_data_read_start(exch, &vols[i],
415 sizeof(hr_vol_info_t));
416 if (rc != EOK) {
417 async_exchange_end(exch);
418 async_forget(req);
419 goto error;
420 }
421 }
422
423 async_exchange_end(exch);
424 async_wait_for(req, &retval);
425 if (retval != EOK) {
426 rc = retval;
427 goto error;
428 }
429
430 if (size == 0) {
431 printf("no active arrays\n");
432 goto error;
433 }
434
435 for (i = 0; i < size; i++) {
436 rc = print_vol_info(i, &vols[i]);
437 if (rc != EOK)
438 goto error;
439 }
440
441error:
442 hr_sess_destroy(hr);
443 if (vols != NULL)
444 free(vols);
445 return rc;
446}
447
448const char *hr_get_vol_status_msg(hr_vol_status_t status)
449{
450 switch (status) {
451 case HR_VOL_NONE:
452 return "NONE/UNKNOWN";
453 case HR_VOL_ONLINE:
454 return "ONLINE";
455 case HR_VOL_FAULTY:
456 return "FAULTY";
457 case HR_VOL_DEGRADED:
458 return "DEGRADED";
459 case HR_VOL_REBUILD:
460 return "REBUILD";
461 default:
462 return "Invalid state value";
463 }
464}
465
466const char *hr_get_ext_status_msg(hr_ext_status_t status)
467{
468 switch (status) {
469 case HR_EXT_NONE:
470 return "NONE/UNKNOWN";
471 case HR_EXT_INVALID:
472 return "INVALID";
473 case HR_EXT_ONLINE:
474 return "ONLINE";
475 case HR_EXT_MISSING:
476 return "MISSING";
477 case HR_EXT_FAILED:
478 return "FAILED";
479 case HR_EXT_REBUILD:
480 return "REBUILD";
481 case HR_EXT_HOTSPARE:
482 return "HOTSPARE";
483 default:
484 return "Invalid state value";
485 }
486}
487
488const char *hr_get_layout_str(hr_layout_t layout)
489{
490 switch (layout) {
491 case HR_RLQ_NONE:
492 return "RAID layout not set";
493 case HR_RLQ_RAID4_0:
494 return "RAID-4 Non-Rotating Parity 0";
495 case HR_RLQ_RAID4_N:
496 return "RAID-4 Non-Rotating Parity N";
497 case HR_RLQ_RAID5_0R:
498 return "RAID-5 Rotating Parity 0 with Data Restart";
499 case HR_RLQ_RAID5_NR:
500 return "RAID-5 Rotating Parity N with Data Restart";
501 case HR_RLQ_RAID5_NC:
502 return "RAID-5 Rotating Parity N with Data Continuation";
503 default:
504 return "Invalid RAID layout";
505 }
506}
507
508const char *hr_get_metadata_type_str(hr_metadata_type_t type)
509{
510 switch (type) {
511 case HR_METADATA_NATIVE:
512 return "Native HelenRAID metadata";
513 case HR_METADATA_GEOM_MIRROR:
514 return "GEOM::MIRROR";
515 case HR_METADATA_GEOM_STRIPE:
516 return "GEOM::STRIPE";
517 default:
518 return "Invalid metadata type value";
519 }
520}
521
522/** @}
523 */
Note: See TracBrowser for help on using the repository browser.