source: mainline/uspace/srv/bd/hr/hr.c@ d082801

Last change on this file since d082801 was d082801, checked in by Miroslav Cimerman <mc@…>, 5 months ago

hr: refactor manual assembly

  • Property mode set to 100644
File size: 10.6 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 hr
30 * @{
31 */
32/**
33 * @file
34 */
35
36#include <adt/list.h>
37#include <async.h>
38#include <bd_srv.h>
39#include <errno.h>
40#include <hr.h>
41#include <io/log.h>
42#include <inttypes.h>
43#include <ipc/hr.h>
44#include <ipc/services.h>
45#include <loc.h>
46#include <task.h>
47#include <stdatomic.h>
48#include <stdio.h>
49#include <stdlib.h>
50#include <str.h>
51#include <str_error.h>
52#include <block.h>
53
54#include "fge.h"
55#include "io.h"
56#include "superblock.h"
57#include "util.h"
58#include "var.h"
59
60loc_srv_t *hr_srv;
61list_t hr_volumes;
62fibril_rwlock_t hr_volumes_lock;
63
64static service_id_t ctl_sid;
65
66static void hr_auto_assemble_srv(ipc_call_t *icall)
67{
68 HR_DEBUG("%s()", __func__);
69
70 errno_t rc;
71 size_t size;
72 size_t assembled_cnt = 0;
73 ipc_call_t call;
74
75 if (!async_data_read_receive(&call, &size)) {
76 async_answer_0(icall, EREFUSED);
77 return;
78 }
79
80 if (size != sizeof(size_t)) {
81 async_answer_0(&call, EINVAL);
82 async_answer_0(icall, EINVAL);
83 return;
84 }
85
86 rc = hr_util_try_assemble(NULL, &assembled_cnt);
87 if (rc != EOK)
88 goto error;
89
90 rc = async_data_read_finalize(&call, &assembled_cnt, size);
91 if (rc != EOK)
92 goto error;
93
94 async_answer_0(icall, EOK);
95 return;
96error:
97 async_answer_0(&call, rc);
98 async_answer_0(icall, rc);
99}
100
101static void hr_assemble_srv(ipc_call_t *icall)
102{
103 HR_DEBUG("%s()", __func__);
104
105 errno_t rc;
106 size_t size, assembled_cnt;
107 hr_config_t *cfg;
108 ipc_call_t call;
109
110 if (!async_data_write_receive(&call, &size)) {
111 async_answer_0(&call, EREFUSED);
112 async_answer_0(icall, EREFUSED);
113 return;
114 }
115
116 if (size != sizeof(hr_config_t)) {
117 async_answer_0(&call, EINVAL);
118 async_answer_0(icall, EINVAL);
119 return;
120 }
121
122 cfg = calloc(1, sizeof(hr_config_t));
123 if (cfg == NULL) {
124 async_answer_0(&call, ENOMEM);
125 async_answer_0(icall, ENOMEM);
126 return;
127 }
128
129 rc = async_data_write_finalize(&call, cfg, size);
130 if (rc != EOK)
131 goto error;
132
133 if (!async_data_read_receive(&call, &size)) {
134 async_answer_0(icall, EREFUSED);
135 return;
136 }
137
138 if (size != sizeof(size_t)) {
139 async_answer_0(icall, EINVAL);
140 return;
141 }
142
143 rc = hr_util_try_assemble(cfg, &assembled_cnt);
144 if (rc != EOK)
145 goto error;
146
147 rc = async_data_read_finalize(&call, &assembled_cnt, size);
148 if (rc != EOK)
149 goto error;
150
151 free(cfg);
152 async_answer_0(icall, EOK);
153 return;
154error:
155 free(cfg);
156 async_answer_0(&call, rc);
157 async_answer_0(icall, rc);
158}
159
160static void hr_create_srv(ipc_call_t *icall)
161{
162 HR_DEBUG("%s()", __func__);
163
164 errno_t rc;
165 size_t i, size;
166 hr_config_t *cfg;
167 hr_volume_t *new_volume;
168 ipc_call_t call;
169
170 if (!async_data_write_receive(&call, &size)) {
171 async_answer_0(&call, EREFUSED);
172 async_answer_0(icall, EREFUSED);
173 return;
174 }
175
176 if (size != sizeof(hr_config_t)) {
177 async_answer_0(&call, EINVAL);
178 async_answer_0(icall, EINVAL);
179 return;
180 }
181
182 cfg = calloc(1, sizeof(hr_config_t));
183 if (cfg == NULL) {
184 async_answer_0(&call, ENOMEM);
185 async_answer_0(icall, ENOMEM);
186 return;
187 }
188
189 rc = async_data_write_finalize(&call, cfg, size);
190 if (rc != EOK) {
191 free(cfg);
192 async_answer_0(&call, rc);
193 async_answer_0(icall, rc);
194 return;
195 }
196
197 /*
198 * If there was a missing device provided
199 * for creation of a new array, abort
200 */
201 for (i = 0; i < cfg->dev_no; i++) {
202 if (cfg->devs[i] == 0) {
203 /*
204 * XXX: own error codes, no need to log this...
205 * its user error not service error
206 */
207 HR_ERROR("missing device provided for array "
208 "creation, aborting");
209 free(cfg);
210 async_answer_0(icall, EINVAL);
211 return;
212 }
213 }
214
215 rc = hr_create_vol_struct(&new_volume, cfg->level);
216 if (rc != EOK) {
217 free(cfg);
218 async_answer_0(icall, rc);
219 return;
220 }
221
222 str_cpy(new_volume->devname, HR_DEVNAME_LEN, cfg->devname);
223 for (i = 0; i < cfg->dev_no; i++)
224 new_volume->extents[i].svc_id = cfg->devs[i];
225 new_volume->level = cfg->level;
226 new_volume->extent_no = cfg->dev_no;
227
228 /* XXX: do proper initing ... */
229 rc = hr_init_devs(new_volume);
230 if (rc != EOK) {
231 free(cfg);
232 free(new_volume);
233 async_answer_0(icall, rc);
234 return;
235 }
236
237 new_volume->hr_ops.init(new_volume);
238 if (rc != EOK)
239 goto error;
240
241 rc = hr_write_meta_to_vol(new_volume);
242 if (rc != EOK)
243 goto error;
244
245 rc = new_volume->hr_ops.create(new_volume);
246 if (rc != EOK)
247 goto error;
248
249 rc = hr_register_volume(new_volume);
250 if (rc != EOK)
251 goto error;
252
253 fibril_rwlock_write_lock(&hr_volumes_lock);
254 list_append(&new_volume->lvolumes, &hr_volumes);
255 fibril_rwlock_write_unlock(&hr_volumes_lock);
256
257 HR_DEBUG("created volume \"%s\" (%" PRIun ")\n", new_volume->devname,
258 new_volume->svc_id);
259
260 free(cfg);
261 async_answer_0(icall, rc);
262 return;
263error:
264 free(cfg);
265 hr_destroy_vol_struct(new_volume);
266 async_answer_0(icall, rc);
267}
268
269static void hr_stop_srv(ipc_call_t *icall)
270{
271 HR_DEBUG("%s()", __func__);
272
273 errno_t rc = EOK;
274 service_id_t svc_id;
275 long fail_extent;
276 hr_volume_t *vol;
277
278 svc_id = ipc_get_arg1(icall);
279 fail_extent = (long)ipc_get_arg2(icall);
280
281 vol = hr_get_volume(svc_id);
282 if (vol == NULL) {
283 async_answer_0(icall, ENOENT);
284 return;
285 }
286
287 if (fail_extent == -1) {
288 rc = hr_remove_volume(svc_id);
289 if (rc != EOK) {
290 async_answer_0(icall, rc);
291 return;
292 }
293 } else {
294 fibril_rwlock_write_lock(&vol->states_lock);
295 fibril_rwlock_read_lock(&vol->extents_lock);
296
297 /* TODO: maybe expose extent state callbacks */
298 hr_update_ext_status(vol, fail_extent, HR_EXT_FAILED);
299 hr_mark_vol_state_dirty(vol);
300
301 fibril_rwlock_read_unlock(&vol->extents_lock);
302 fibril_rwlock_write_unlock(&vol->states_lock);
303
304 vol->hr_ops.status_event(vol);
305 }
306 async_answer_0(icall, rc);
307}
308
309static void hr_add_hotspare_srv(ipc_call_t *icall)
310{
311 HR_DEBUG("%s()", __func__);
312
313 errno_t rc = EOK;
314 service_id_t vol_svc_id;
315 service_id_t hotspare;
316 hr_volume_t *vol;
317
318 vol_svc_id = ipc_get_arg1(icall);
319 hotspare = ipc_get_arg2(icall);
320
321 vol = hr_get_volume(vol_svc_id);
322 if (vol == NULL) {
323 async_answer_0(icall, ENOENT);
324 return;
325 }
326
327 if (vol->hr_ops.add_hotspare == NULL) {
328 HR_DEBUG("hr_add_hotspare(): not supported on RAID level %d\n",
329 vol->level);
330 async_answer_0(icall, ENOTSUP);
331 return;
332 }
333
334 rc = vol->hr_ops.add_hotspare(vol, hotspare);
335
336 async_answer_0(icall, rc);
337}
338
339static void hr_print_status_srv(ipc_call_t *icall)
340{
341 HR_DEBUG("%s()", __func__);
342
343 errno_t rc;
344 size_t vol_cnt = 0;
345 hr_vol_info_t info;
346 ipc_call_t call;
347 size_t size;
348
349 fibril_rwlock_read_lock(&hr_volumes_lock);
350
351 vol_cnt = list_count(&hr_volumes);
352
353 if (!async_data_read_receive(&call, &size)) {
354 rc = EREFUSED;
355 goto error;
356 }
357
358 if (size != sizeof(size_t)) {
359 rc = EINVAL;
360 goto error;
361 }
362
363 rc = async_data_read_finalize(&call, &vol_cnt, size);
364 if (rc != EOK)
365 goto error;
366
367 list_foreach(hr_volumes, lvolumes, hr_volume_t, vol) {
368 memcpy(info.extents, vol->extents,
369 sizeof(hr_extent_t) * HR_MAX_EXTENTS);
370 memcpy(info.hotspares, vol->hotspares,
371 sizeof(hr_extent_t) * HR_MAX_HOTSPARES);
372 info.svc_id = vol->svc_id;
373 info.extent_no = vol->extent_no;
374 info.hotspare_no = vol->hotspare_no;
375 info.level = vol->level;
376 /* print usable number of blocks */
377 info.nblocks = vol->data_blkno;
378 info.strip_size = vol->strip_size;
379 info.bsize = vol->bsize;
380 info.status = vol->status;
381 info.layout = vol->layout;
382
383 if (!async_data_read_receive(&call, &size)) {
384 rc = EREFUSED;
385 goto error;
386 }
387
388 if (size != sizeof(hr_vol_info_t)) {
389 rc = EINVAL;
390 goto error;
391 }
392
393 rc = async_data_read_finalize(&call, &info, size);
394 if (rc != EOK)
395 goto error;
396 }
397
398 fibril_rwlock_read_unlock(&hr_volumes_lock);
399 async_answer_0(icall, EOK);
400 return;
401error:
402 fibril_rwlock_read_unlock(&hr_volumes_lock);
403 async_answer_0(&call, rc);
404 async_answer_0(icall, rc);
405}
406
407static void hr_ctl_conn(ipc_call_t *icall, void *arg)
408{
409 HR_DEBUG("%s()", __func__);
410
411 async_accept_0(icall);
412
413 while (true) {
414 ipc_call_t call;
415 async_get_call(&call);
416 sysarg_t method = ipc_get_imethod(&call);
417
418 if (!method) {
419 async_answer_0(&call, EOK);
420 return;
421 }
422
423 switch (method) {
424 case HR_CREATE:
425 hr_create_srv(&call);
426 break;
427 case HR_ASSEMBLE:
428 hr_assemble_srv(&call);
429 break;
430 case HR_AUTO_ASSEMBLE:
431 hr_auto_assemble_srv(&call);
432 break;
433 case HR_STOP:
434 hr_stop_srv(&call);
435 break;
436 case HR_ADD_HOTSPARE:
437 hr_add_hotspare_srv(&call);
438 break;
439 case HR_STATUS:
440 hr_print_status_srv(&call);
441 break;
442 default:
443 async_answer_0(&call, EINVAL);
444 }
445 }
446}
447
448static void hr_client_conn(ipc_call_t *icall, void *arg)
449{
450 HR_DEBUG("%s()", __func__);
451
452 hr_volume_t *vol;
453
454 service_id_t svc_id = ipc_get_arg2(icall);
455
456 if (svc_id == ctl_sid) {
457 hr_ctl_conn(icall, arg);
458 } else {
459 HR_DEBUG("bd_conn()\n");
460 vol = hr_get_volume(svc_id);
461 if (vol == NULL)
462 async_answer_0(icall, ENOENT);
463 bd_conn(icall, &vol->hr_bds);
464 }
465}
466
467int main(int argc, char **argv)
468{
469 errno_t rc;
470
471 printf("%s: HelenRAID server\n", NAME);
472
473 rc = log_init(NAME);
474 if (rc != EOK) {
475 printf("%s: failed to initialize logging\n", NAME);
476 return 1;
477 }
478
479 fibril_rwlock_initialize(&hr_volumes_lock);
480 list_initialize(&hr_volumes);
481
482 async_set_fallback_port_handler(hr_client_conn, NULL);
483
484 rc = loc_server_register(NAME, &hr_srv);
485 if (rc != EOK) {
486 HR_ERROR("failed registering server: %s", str_error(rc));
487 return EEXIST;
488 }
489
490 rc = loc_service_register(hr_srv, SERVICE_NAME_HR, &ctl_sid);
491 if (rc != EOK) {
492 HR_ERROR("failed registering service: %s", str_error(rc));
493 return EEXIST;
494 }
495
496 printf("%s: accepting connections\n", NAME);
497 task_retval(0);
498 async_manager();
499
500 return 0;
501}
502
503/** @}
504 */
Note: See TracBrowser for help on using the repository browser.