source: mainline/uspace/lib/device/src/hr.c

Last change on this file was 2192a01, checked in by Miroslav Cimerman <mc@…>, 9 hours ago

hr: basic Linux Multiple Device RAID format support

  • Property mode set to 100644
File size: 11.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
[af4ecb76]211/** Stop/deactivate volume.
212 *
213 * @param hr Server session
214 * @param devname Volume name
215 *
216 * @return EOK on success or an error code
217 */
[fc265b4]218errno_t hr_stop(hr_t *hr, const char *devname)
[a19d7fc4]219{
220 errno_t rc;
221 async_exch_t *exch;
222 service_id_t svc_id;
223
224 rc = loc_service_get_id(devname, &svc_id, 0);
225 if (rc != EOK)
226 return rc;
227
228 exch = async_exchange_begin(hr->sess);
229 if (exch == NULL) {
230 rc = EINVAL;
231 goto error;
232 }
[d1d355f]233
234 rc = async_req_1_0(exch, HR_STOP, svc_id);
235 async_exchange_end(exch);
236error:
237 return rc;
238}
239
[af4ecb76]240/** Stop/deactivate all volumes.
241 *
242 * @param hr Server session
243 *
244 * @return EOK on success or an error code
245 */
[fc265b4]246errno_t hr_stop_all(hr_t *hr)
[d1d355f]247{
248 async_exch_t *exch;
249 errno_t rc;
250
251 exch = async_exchange_begin(hr->sess);
252 if (exch == NULL) {
253 rc = EINVAL;
254 goto error;
255 }
256
257 rc = async_req_0_0(exch, HR_STOP_ALL);
258 async_exchange_end(exch);
259error:
260 return rc;
261}
262
[af4ecb76]263/** Fail an extent in volume.
264 *
265 * @param hr Server session
266 * @param volume_name Volume name
267 * @param extent Extent index to fail
268 *
269 * @return EOK on success or an error code
270 */
[fc265b4]271errno_t hr_fail_extent(hr_t *hr, const char *volume_name, unsigned long extent)
[d1d355f]272{
273 errno_t rc;
274 async_exch_t *exch;
275 service_id_t vol_svc_id;
276
277 rc = loc_service_get_id(volume_name, &vol_svc_id, 0);
278 if (rc != EOK)
279 return rc;
280
281 exch = async_exchange_begin(hr->sess);
282 if (exch == NULL) {
283 rc = EINVAL;
284 goto error;
285 }
286
287 rc = async_req_2_0(exch, HR_FAIL_EXTENT, vol_svc_id, extent);
[a19d7fc4]288 async_exchange_end(exch);
289error:
290 return rc;
291}
292
[af4ecb76]293/** Add a hotspare to volume.
294 *
295 * @param hr Server session
296 * @param volume_name Volume name
297 * @param hotspare Hotspare service name
298 *
299 * @return EOK on success or an error code
300 */
[fc265b4]301errno_t hr_add_hotspare(hr_t *hr, const char *volume_name, const char *hotspare)
[5b320ac]302{
303 errno_t rc;
304 async_exch_t *exch;
[d1d355f]305 service_id_t vol_svc_id, hs_svc_id;
306
307 rc = loc_service_get_id(volume_name, &vol_svc_id, 0);
308 if (rc != EOK)
309 return rc;
310
311 rc = loc_service_get_id(hotspare, &hs_svc_id, 0);
312 if (rc != EOK)
313 return rc;
[5b320ac]314
315 exch = async_exchange_begin(hr->sess);
316 if (exch == NULL) {
317 rc = EINVAL;
318 goto error;
319 }
320
321 rc = async_req_2_0(exch, HR_ADD_HOTSPARE, vol_svc_id, hs_svc_id);
322 async_exchange_end(exch);
323error:
324 return rc;
325}
326
[e0bbecb]327/** Get state of volumes.
[af4ecb76]328 *
[e0bbecb]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
[af4ecb76]332 *
333 * @return EOK on success or an error code
334 */
[e0bbecb]335errno_t hr_get_vol_states(hr_t *hr, hr_pair_vol_state_t **rpairs, size_t *rcnt)
[095a989]336{
337 errno_t rc, retval;
338 async_exch_t *exch;
339 aid_t req;
[e0bbecb]340 size_t cnt, i;
341 hr_pair_vol_state_t *pairs = NULL;
[095a989]342
343 exch = async_exchange_begin(hr->sess);
[a19d7fc4]344 if (exch == NULL) {
345 rc = EINVAL;
346 goto error;
347 }
[095a989]348
[e0bbecb]349 req = async_send_0(exch, HR_GET_VOL_STATES, NULL);
350 rc = async_data_read_start(exch, &cnt, sizeof(size_t));
[095a989]351 if (rc != EOK) {
352 async_exchange_end(exch);
353 async_forget(req);
354 return rc;
355 }
356
[e0bbecb]357 pairs = calloc(cnt, sizeof(*pairs));
358 if (pairs == NULL) {
[095a989]359 async_exchange_end(exch);
360 async_forget(req);
361 return ENOMEM;
362 }
363
[e0bbecb]364 for (i = 0; i < cnt; i++) {
365 rc = async_data_read_start(exch, &pairs[i], sizeof(*pairs));
[095a989]366 if (rc != EOK) {
367 async_exchange_end(exch);
368 async_forget(req);
369 goto error;
370 }
371 }
372
373 async_exchange_end(exch);
374 async_wait_for(req, &retval);
375 if (retval != EOK) {
376 rc = retval;
377 goto error;
378 }
379
[e0bbecb]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);
[a19d7fc4]424 goto error;
425 }
426
[e0bbecb]427 async_wait_for(req, &retval);
428 if (retval != EOK) {
429 rc = retval;
430 goto error;
[095a989]431 }
432
433error:
434 return rc;
435}
436
[155d34f]437/** Get volume state string.
438 *
439 * @param state State value
440 *
441 * @return State string
442 */
[56602e0]443const char *hr_get_vol_state_str(hr_vol_state_t state)
[e47a032]444{
[56602e0]445 switch (state) {
[e24c064]446 case HR_VOL_NONE:
447 return "NONE/UNKNOWN";
[263a2389]448 case HR_VOL_OPTIMAL:
449 return "OPTIMAL";
[e47a032]450 case HR_VOL_FAULTY:
451 return "FAULTY";
[13ce552]452 case HR_VOL_DEGRADED:
453 return "DEGRADED";
[5b320ac]454 case HR_VOL_REBUILD:
455 return "REBUILD";
[e47a032]456 default:
[e24c064]457 return "Invalid state value";
[e47a032]458 }
459}
460
[155d34f]461/** Get extent state string.
462 *
463 * @param state State value
464 *
465 * @return State string
466 */
[56602e0]467const char *hr_get_ext_state_str(hr_ext_state_t state)
[e47a032]468{
[56602e0]469 switch (state) {
[e24c064]470 case HR_EXT_NONE:
471 return "NONE/UNKNOWN";
[3a68baa]472 case HR_EXT_INVALID:
473 return "INVALID";
[e47a032]474 case HR_EXT_ONLINE:
475 return "ONLINE";
476 case HR_EXT_MISSING:
477 return "MISSING";
478 case HR_EXT_FAILED:
479 return "FAILED";
[5b320ac]480 case HR_EXT_REBUILD:
481 return "REBUILD";
482 case HR_EXT_HOTSPARE:
483 return "HOTSPARE";
[e47a032]484 default:
[e24c064]485 return "Invalid state value";
[e47a032]486 }
487}
488
[155d34f]489/** Get volume layout string.
490 *
491 * @param layout Layout value
492 *
493 * @return Layout string
494 */
[fb06476f]495const char *hr_get_layout_str(hr_layout_t layout)
[4066371]496{
[fb06476f]497 switch (layout) {
[0fce1a6]498 case HR_LAYOUT_NONE:
[fb06476f]499 return "RAID layout not set";
[0fce1a6]500 case HR_LAYOUT_RAID4_0:
[fb06476f]501 return "RAID-4 Non-Rotating Parity 0";
[0fce1a6]502 case HR_LAYOUT_RAID4_N:
[fb06476f]503 return "RAID-4 Non-Rotating Parity N";
[0fce1a6]504 case HR_LAYOUT_RAID5_0R:
[fb06476f]505 return "RAID-5 Rotating Parity 0 with Data Restart";
[0fce1a6]506 case HR_LAYOUT_RAID5_NR:
[fb06476f]507 return "RAID-5 Rotating Parity N with Data Restart";
[0fce1a6]508 case HR_LAYOUT_RAID5_NC:
[fb06476f]509 return "RAID-5 Rotating Parity N with Data Continuation";
[4066371]510 default:
[fb06476f]511 return "Invalid RAID layout";
[4066371]512 }
513}
514
[e0bbecb]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
[155d34f]537/** Get volume metadata type string.
538 *
539 * @param type Metadata type value
540 *
541 * @return Metadata type string
542 */
[b883aa8]543const char *hr_get_metadata_type_str(hr_metadata_type_t type)
544{
545 switch (type) {
546 case HR_METADATA_NATIVE:
[d220b7d]547 return "HelenRAID native";
[b883aa8]548 case HR_METADATA_GEOM_MIRROR:
549 return "GEOM::MIRROR";
550 case HR_METADATA_GEOM_STRIPE:
551 return "GEOM::STRIPE";
[c24f96b]552 case HR_METADATA_SOFTRAID:
553 return "OpenBSD softraid";
[2192a01]554 case HR_METADATA_MD:
555 return "Linux Multiple Device";
[b883aa8]556 default:
557 return "Invalid metadata type value";
558 }
559}
560
[94d84a0]561/** @}
562 */
Note: See TracBrowser for help on using the repository browser.