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

Last change on this file was 73a2780, checked in by Miroslav Cimerman <mc@…>, 11 days ago

hr: remove old comments

  • Property mode set to 100644
File size: 14.6 KB
RevLine 
[94d84a0]1/*
[bc3d695]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 hr
30 * @{
31 */
32/**
[31eb568]33 * @file hr.c
34 * @brief HelenRAID server methods.
[94d84a0]35 */
36
[b04f7af]37#include <adt/list.h>
[94d84a0]38#include <async.h>
39#include <bd_srv.h>
40#include <errno.h>
41#include <hr.h>
42#include <io/log.h>
43#include <ipc/hr.h>
44#include <ipc/services.h>
45#include <loc.h>
46#include <task.h>
47#include <stdio.h>
48#include <stdlib.h>
[68e357e]49#include <str.h>
[94d84a0]50#include <str_error.h>
[b04f7af]51#include <block.h>
[94d84a0]52
[b0f1366]53#include "util.h"
[94d84a0]54#include "var.h"
55
[6d0fc11]56static void hr_assemble_srv(ipc_call_t *);
57static void hr_auto_assemble_srv(ipc_call_t *);
58static void hr_stop_srv(ipc_call_t *);
[d1d355f]59static void hr_stop_all_srv(ipc_call_t *);
[6d0fc11]60static void hr_add_hotspare_srv(ipc_call_t *);
[e0bbecb]61static void hr_get_vol_states_srv(ipc_call_t *);
[31eb568]62static void hr_ctl_conn(ipc_call_t *);
[b247c714]63static void hr_call_handler(ipc_call_t *, void *);
[6d0fc11]64
[94d84a0]65loc_srv_t *hr_srv;
[8b51009]66list_t hr_volumes;
67fibril_rwlock_t hr_volumes_lock;
[94d84a0]68
69static service_id_t ctl_sid;
70
[31eb568]71/** Volume creation (server).
72 *
73 * Creates HelenRAID volume from parameters and
74 * devices specified in hr_config_t.
75 *
76 * @param icall hr_config_t
77 */
[6d0fc11]78static void hr_create_srv(ipc_call_t *icall)
[a19d7fc4]79{
[8b51009]80 HR_DEBUG("%s()", __func__);
[a19d7fc4]81
[8b51009]82 errno_t rc;
[6d0fc11]83 size_t i, size;
84 hr_config_t *cfg;
[50603405]85 hr_volume_t *vol;
[8b51009]86 ipc_call_t call;
87
[6d0fc11]88 if (!async_data_write_receive(&call, &size)) {
89 async_answer_0(&call, EREFUSED);
[8b51009]90 async_answer_0(icall, EREFUSED);
91 return;
[a19d7fc4]92 }
93
[6d0fc11]94 if (size != sizeof(hr_config_t)) {
[d082801]95 async_answer_0(&call, EINVAL);
[8b51009]96 async_answer_0(icall, EINVAL);
97 return;
98 }
[a19d7fc4]99
[6d0fc11]100 cfg = calloc(1, sizeof(hr_config_t));
101 if (cfg == NULL) {
102 async_answer_0(&call, ENOMEM);
103 async_answer_0(icall, ENOMEM);
104 return;
105 }
106
107 rc = async_data_write_finalize(&call, cfg, size);
108 if (rc != EOK) {
109 free(cfg);
110 async_answer_0(&call, rc);
111 async_answer_0(icall, rc);
112 return;
113 }
114
[15e51b05]115 if (cfg->dev_no > HR_MAX_EXTENTS) {
116 HR_ERROR("provided %u devices (max = %u)",
117 (unsigned)cfg->dev_no, HR_MAX_EXTENTS);
118 free(cfg);
119 async_answer_0(icall, ELIMIT);
120 return;
121 }
122
[6d0fc11]123 /*
124 * If there was a missing device provided
[af73327a]125 * for creation of a new volume, abort
[6d0fc11]126 */
127 for (i = 0; i < cfg->dev_no; i++) {
128 if (cfg->devs[i] == 0) {
[af73327a]129 HR_ERROR("missing device provided for volume "
[6d0fc11]130 "creation, aborting");
131 free(cfg);
132 async_answer_0(icall, EINVAL);
133 return;
134 }
135 }
136
[150adbd2]137 hr_metadata_type_t meta_type;
138 if (cfg->vol_flags & HR_VOL_FLAG_NOOP_META)
139 meta_type = HR_METADATA_NOOP;
140 else
141 meta_type = HR_METADATA_NATIVE;
142
[95ca19d]143 rc = hr_create_vol_struct(&vol, cfg->level, cfg->devname, meta_type,
144 cfg->vol_flags);
[6d0fc11]145 if (rc != EOK) {
146 free(cfg);
147 async_answer_0(icall, rc);
148 return;
149 }
150
[50603405]151 rc = hr_init_extents_from_cfg(vol, cfg);
[baa4929]152 if (rc != EOK)
153 goto error;
[6d0fc11]154
[50603405]155 vol->hr_ops.init(vol);
[d082801]156 if (rc != EOK)
157 goto error;
158
[78433bb]159 rc = vol->meta_ops->init_vol2meta(vol);
[0277ec2]160 if (rc != EOK)
161 goto error;
162
[50603405]163 rc = vol->hr_ops.create(vol);
[d082801]164 if (rc != EOK)
165 goto error;
166
[e0695ce]167 vol->meta_ops->save(vol, WITH_STATE_CALLBACK);
[6d0fc11]168
[50603405]169 rc = hr_register_volume(vol);
[6d0fc11]170 if (rc != EOK)
171 goto error;
172
173 fibril_rwlock_write_lock(&hr_volumes_lock);
[50603405]174 list_append(&vol->lvolumes, &hr_volumes);
[6d0fc11]175 fibril_rwlock_write_unlock(&hr_volumes_lock);
176
[c5b60e25]177 HR_NOTE("created volume \"%s\" (%" PRIun ")\n", vol->devname,
178 vol->svc_id);
[6d0fc11]179
180 free(cfg);
181 async_answer_0(icall, rc);
[d082801]182 return;
183error:
[6d0fc11]184 free(cfg);
[50603405]185 hr_destroy_vol_struct(vol);
[d082801]186 async_answer_0(icall, rc);
187}
188
[31eb568]189/** Manual volume assembly (server).
190 *
191 * Tries to assemble a volume from devices in hr_config_t and
192 * sends the number of successful volumes assembled back to the
193 * client.
194 *
195 * @param icall hr_config_t
196 */
[d082801]197static void hr_assemble_srv(ipc_call_t *icall)
198{
199 HR_DEBUG("%s()", __func__);
200
201 errno_t rc;
202 size_t size, assembled_cnt;
203 hr_config_t *cfg;
204 ipc_call_t call;
205
206 if (!async_data_write_receive(&call, &size)) {
207 async_answer_0(&call, EREFUSED);
208 async_answer_0(icall, EREFUSED);
[8b51009]209 return;
210 }
[a19d7fc4]211
[d082801]212 if (size != sizeof(hr_config_t)) {
213 async_answer_0(&call, EINVAL);
214 async_answer_0(icall, EINVAL);
215 return;
216 }
217
218 cfg = calloc(1, sizeof(hr_config_t));
219 if (cfg == NULL) {
220 async_answer_0(&call, ENOMEM);
221 async_answer_0(icall, ENOMEM);
222 return;
223 }
224
225 rc = async_data_write_finalize(&call, cfg, size);
226 if (rc != EOK)
227 goto error;
228
229 if (!async_data_read_receive(&call, &size)) {
230 async_answer_0(icall, EREFUSED);
[8b51009]231 return;
[a19d7fc4]232 }
233
[d082801]234 if (size != sizeof(size_t)) {
235 async_answer_0(icall, EINVAL);
236 return;
237 }
238
239 rc = hr_util_try_assemble(cfg, &assembled_cnt);
240 if (rc != EOK)
241 goto error;
242
243 rc = async_data_read_finalize(&call, &assembled_cnt, size);
244 if (rc != EOK)
245 goto error;
246
247 free(cfg);
[8b51009]248 async_answer_0(icall, EOK);
[d082801]249 return;
250error:
251 free(cfg);
252 async_answer_0(&call, rc);
253 async_answer_0(icall, rc);
[a19d7fc4]254}
255
[31eb568]256/** Automatic volume assembly (server).
257 *
258 * Tries to assemble a volume from devices in disk location
259 * category and sends the number of successful volumes assembled
260 * back to client.
261 */
[6d0fc11]262static void hr_auto_assemble_srv(ipc_call_t *icall)
[94d84a0]263{
[a57dde4]264 HR_DEBUG("%s()", __func__);
[94d84a0]265
266 errno_t rc;
[6d0fc11]267 size_t size;
268 size_t assembled_cnt = 0;
[68e357e]269 ipc_call_t call;
[94d84a0]270
[6d0fc11]271 if (!async_data_read_receive(&call, &size)) {
[68e357e]272 async_answer_0(icall, EREFUSED);
[94d84a0]273 return;
274 }
275
[6d0fc11]276 if (size != sizeof(size_t)) {
[68e357e]277 async_answer_0(&call, EINVAL);
278 async_answer_0(icall, EINVAL);
[94d84a0]279 return;
280 }
281
[6d0fc11]282 rc = hr_util_try_assemble(NULL, &assembled_cnt);
[b0f1366]283 if (rc != EOK)
284 goto error;
285
[6d0fc11]286 rc = async_data_read_finalize(&call, &assembled_cnt, size);
[8a65373]287 if (rc != EOK)
288 goto error;
289
[6d0fc11]290 async_answer_0(icall, EOK);
[b0f1366]291 return;
292error:
[6d0fc11]293 async_answer_0(&call, rc);
[b0f1366]294 async_answer_0(icall, rc);
[94d84a0]295}
296
[31eb568]297/** Volume deactivation (server).
298 *
299 * Deactivates/detaches specified volume.
300 */
[a19d7fc4]301static void hr_stop_srv(ipc_call_t *icall)
302{
[a57dde4]303 HR_DEBUG("%s()", __func__);
[a19d7fc4]304
[cf28ffd3]305 errno_t rc = EOK;
[a19d7fc4]306 service_id_t svc_id;
307
308 svc_id = ipc_get_arg1(icall);
309
[c9ce6d22]310 rc = hr_remove_volume(svc_id);
[d1d355f]311
312 async_answer_0(icall, rc);
313}
314
[31eb568]315/** Automatic volume deactivation (server).
316 *
317 * Tries to deactivate/detach all volumes.
318 */
[d1d355f]319static void hr_stop_all_srv(ipc_call_t *icall)
320{
321 HR_DEBUG("%s()", __func__);
322
[c9ce6d22]323 service_id_t *vol_svcs = NULL;
[d1d355f]324 errno_t rc = EOK;
[c9ce6d22]325 size_t i, vol_cnt;
[d1d355f]326
[c9ce6d22]327 rc = hr_get_volume_svcs(&vol_cnt, &vol_svcs);
328 if (rc != EOK)
329 goto fail;
[7b359f5]330
[ba65caf5]331 for (i = 0; i < vol_cnt; i++) {
332 errno_t rc2 = hr_remove_volume(vol_svcs[i]);
333 if (rc2 == EBUSY)
334 rc = EBUSY;
335 }
[d1d355f]336
[c9ce6d22]337fail:
338 if (vol_svcs != NULL)
339 free(vol_svcs);
[a19d7fc4]340 async_answer_0(icall, rc);
341}
342
[31eb568]343/** Simulate volume extent failure (server).
344 *
345 * Changes the specified extent's state to FAULTY.
346 * Other extents' metadata are marked as dirty, therefore
347 * it effectively invalides the specified extent as well
348 * for further uses.
349 */
[d1d355f]350static void hr_fail_extent_srv(ipc_call_t *icall)
351{
352 HR_DEBUG("%s()", __func__);
353
354 service_id_t svc_id;
[13ada52]355 size_t extent_idx_to_fail;
[d1d355f]356 hr_volume_t *vol;
357
358 svc_id = (service_id_t)ipc_get_arg1(icall);
[13ada52]359 extent_idx_to_fail = (size_t)ipc_get_arg2(icall);
[d1d355f]360
361 vol = hr_get_volume(svc_id);
362 if (vol == NULL) {
363 async_answer_0(icall, ENOENT);
364 return;
365 }
366
[6aafb48]367 fibril_rwlock_write_lock(&vol->extents_lock);
[ac4b70b]368 fibril_rwlock_write_lock(&vol->states_lock);
[d1d355f]369
[137f7cf5]370 hr_extent_t *ext = &vol->extents[extent_idx_to_fail];
371
[13ada52]372 switch (ext->state) {
[ac4b70b]373 case HR_EXT_NONE:
374 case HR_EXT_MISSING:
375 case HR_EXT_FAILED:
376 fibril_rwlock_write_unlock(&vol->states_lock);
[6aafb48]377 fibril_rwlock_write_unlock(&vol->extents_lock);
[ac4b70b]378 async_answer_0(icall, EINVAL);
379 return;
380 default:
[13ada52]381 hr_update_ext_state(vol, extent_idx_to_fail, HR_EXT_FAILED);
382 (void)vol->meta_ops->erase_block(ext->svc_id);
[6aafb48]383 block_fini(ext->svc_id);
384 ext->svc_id = 0;
[ac4b70b]385 hr_mark_vol_state_dirty(vol);
386 }
[d1d355f]387
388 fibril_rwlock_write_unlock(&vol->states_lock);
[6aafb48]389 fibril_rwlock_write_unlock(&vol->extents_lock);
[d1d355f]390
[da80de9]391 vol->hr_ops.vol_state_eval(vol);
[d1d355f]392
393 async_answer_0(icall, EOK);
394}
395
[31eb568]396/** Add hotspare to volume (server).
397 *
398 * Adds hotspare to a volume.
399 */
[5b320ac]400static void hr_add_hotspare_srv(ipc_call_t *icall)
401{
[a57dde4]402 HR_DEBUG("%s()", __func__);
[5b320ac]403
404 errno_t rc = EOK;
405 service_id_t vol_svc_id;
406 service_id_t hotspare;
407 hr_volume_t *vol;
408
409 vol_svc_id = ipc_get_arg1(icall);
410 hotspare = ipc_get_arg2(icall);
411
412 vol = hr_get_volume(vol_svc_id);
413 if (vol == NULL) {
414 async_answer_0(icall, ENOENT);
415 return;
416 }
417
[996d31ac]418 if (vol->level == HR_LVL_0) {
419 HR_NOTE("hotspare not supported on RAID level = %s\n",
420 hr_get_level_str(vol->level));
421 async_answer_0(icall, ENOTSUP);
422 return;
423 }
424
425 if (!(vol->meta_ops->get_flags() & HR_METADATA_HOTSPARE_SUPPORT)) {
426 HR_NOTE("hotspare not supported on metadata type = %s\n",
[c6d2af8]427 hr_get_metadata_type_str(vol->meta_ops->get_type()));
[5b320ac]428 async_answer_0(icall, ENOTSUP);
429 return;
430 }
431
[996d31ac]432 rc = hr_util_add_hotspare(vol, hotspare);
433
434 vol->hr_ops.vol_state_eval(vol);
[5b320ac]435
436 async_answer_0(icall, rc);
437}
438
[e0bbecb]439/** Send volume states.
[31eb568]440 *
[e0bbecb]441 * Sends the client pairs of (volume service_id, state).
[31eb568]442 */
[e0bbecb]443static void hr_get_vol_states_srv(ipc_call_t *icall)
[095a989]444{
[a57dde4]445 HR_DEBUG("%s()", __func__);
[095a989]446
447 errno_t rc;
448 size_t vol_cnt = 0;
[e0bbecb]449 hr_pair_vol_state_t pair;
[095a989]450 ipc_call_t call;
451 size_t size;
452
[8b51009]453 fibril_rwlock_read_lock(&hr_volumes_lock);
[095a989]454
455 vol_cnt = list_count(&hr_volumes);
456
457 if (!async_data_read_receive(&call, &size)) {
458 rc = EREFUSED;
459 goto error;
460 }
461
[e0bbecb]462 if (size != sizeof(vol_cnt)) {
[095a989]463 rc = EINVAL;
464 goto error;
465 }
466
467 rc = async_data_read_finalize(&call, &vol_cnt, size);
468 if (rc != EOK)
469 goto error;
470
[b235c67]471 list_foreach(hr_volumes, lvolumes, hr_volume_t, vol) {
[e0bbecb]472 pair.svc_id = vol->svc_id;
473 pair.state = vol->state;
[095a989]474
475 if (!async_data_read_receive(&call, &size)) {
476 rc = EREFUSED;
477 goto error;
478 }
479
[e0bbecb]480 if (size != sizeof(pair)) {
[095a989]481 rc = EINVAL;
482 goto error;
483 }
484
[e0bbecb]485 rc = async_data_read_finalize(&call, &pair, size);
[095a989]486 if (rc != EOK)
487 goto error;
488 }
489
[8b51009]490 fibril_rwlock_read_unlock(&hr_volumes_lock);
[095a989]491 async_answer_0(icall, EOK);
492 return;
493error:
[8b51009]494 fibril_rwlock_read_unlock(&hr_volumes_lock);
[095a989]495 async_answer_0(&call, rc);
496 async_answer_0(icall, rc);
497}
498
[e0bbecb]499/** Send volume info.
500 *
501 * Sends the client volume info.
502 */
503static void hr_get_vol_info_srv(ipc_call_t *icall)
504{
505 HR_DEBUG("%s()", __func__);
506
507 errno_t rc;
508 size_t size;
509 ipc_call_t call;
510 service_id_t svc_id;
511 hr_vol_info_t info;
512 hr_volume_t *vol;
513
514 if (!async_data_write_receive(&call, &size)) {
515 rc = EREFUSED;
516 goto error;
517 }
518
519 if (size != sizeof(service_id_t)) {
520 rc = EINVAL;
521 goto error;
522 }
523
524 rc = async_data_write_finalize(&call, &svc_id, size);
525 if (rc != EOK)
526 goto error;
527
528 vol = hr_get_volume(svc_id);
529 if (vol == NULL) {
530 rc = ENOENT;
531 goto error;
532 }
533
534 memcpy(info.extents, vol->extents,
535 sizeof(hr_extent_t) * HR_MAX_EXTENTS);
536 memcpy(info.hotspares, vol->hotspares,
537 sizeof(hr_extent_t) * HR_MAX_HOTSPARES);
538 info.svc_id = vol->svc_id;
539 info.extent_no = vol->extent_no;
540 info.hotspare_no = vol->hotspare_no;
541 info.level = vol->level;
542 info.data_blkno = vol->data_blkno;
[f34568c]543 info.rebuild_blk = vol->rebuild_blk;
[e0bbecb]544 info.strip_size = vol->strip_size;
545 info.bsize = vol->bsize;
546 info.state = vol->state;
547 info.layout = vol->layout;
548 info.meta_type = vol->meta_ops->get_type();
549 memcpy(info.devname, vol->devname, HR_DEVNAME_LEN);
[95ca19d]550 info.vflags = vol->vflags;
[e0bbecb]551
552 if (!async_data_read_receive(&call, &size)) {
553 rc = EREFUSED;
554 goto error;
555 }
556
557 if (size != sizeof(info)) {
558 rc = EINVAL;
559 goto error;
560 }
561
562 rc = async_data_read_finalize(&call, &info, size);
563 if (rc != EOK)
564 goto error;
565
566 async_answer_0(icall, EOK);
567 return;
568error:
569 async_answer_0(&call, rc);
570 async_answer_0(icall, rc);
571}
572
[31eb568]573/** HelenRAID server control IPC methods crossroad.
574 */
575static void hr_ctl_conn(ipc_call_t *icall)
[94d84a0]576{
[a57dde4]577 HR_DEBUG("%s()", __func__);
[94d84a0]578
579 async_accept_0(icall);
580
581 while (true) {
582 ipc_call_t call;
583 async_get_call(&call);
584 sysarg_t method = ipc_get_imethod(&call);
585
586 if (!method) {
587 async_answer_0(&call, EOK);
588 return;
589 }
590
591 switch (method) {
592 case HR_CREATE:
[d082801]593 hr_create_srv(&call);
[94d84a0]594 break;
[b0f1366]595 case HR_ASSEMBLE:
[d082801]596 hr_assemble_srv(&call);
[b0f1366]597 break;
[8b51009]598 case HR_AUTO_ASSEMBLE:
599 hr_auto_assemble_srv(&call);
600 break;
[a19d7fc4]601 case HR_STOP:
602 hr_stop_srv(&call);
603 break;
[d1d355f]604 case HR_STOP_ALL:
605 hr_stop_all_srv(&call);
606 break;
607 case HR_FAIL_EXTENT:
608 hr_fail_extent_srv(&call);
609 break;
[5b320ac]610 case HR_ADD_HOTSPARE:
611 hr_add_hotspare_srv(&call);
612 break;
[e0bbecb]613 case HR_GET_VOL_STATES:
614 hr_get_vol_states_srv(&call);
615 break;
616 case HR_GET_VOL_INFO:
617 hr_get_vol_info_srv(&call);
[a19d7fc4]618 break;
[94d84a0]619 default:
620 async_answer_0(&call, EINVAL);
621 }
622 }
623}
624
[31eb568]625/** HelenRAID server IPC method crossroad.
626 *
627 * Distinguishes between control IPC and block device
628 * IPC calls.
629 */
[b247c714]630static void hr_call_handler(ipc_call_t *icall, void *arg)
[94d84a0]631{
[a57dde4]632 HR_DEBUG("%s()", __func__);
[94d84a0]633
634 hr_volume_t *vol;
635
[da5c257]636 service_id_t svc_id = ipc_get_arg2(icall);
[94d84a0]637
638 if (svc_id == ctl_sid) {
[31eb568]639 hr_ctl_conn(icall);
[94d84a0]640 } else {
641 vol = hr_get_volume(svc_id);
[038a8d0]642 if (vol == NULL) {
[7bfe468]643 async_answer_0(icall, ENOENT);
[038a8d0]644 return;
645 }
[94d84a0]646 bd_conn(icall, &vol->hr_bds);
647 }
648}
649
650int main(int argc, char **argv)
651{
652 errno_t rc;
653
654 printf("%s: HelenRAID server\n", NAME);
655
656 rc = log_init(NAME);
657 if (rc != EOK) {
658 printf("%s: failed to initialize logging\n", NAME);
659 return 1;
660 }
661
[8b51009]662 fibril_rwlock_initialize(&hr_volumes_lock);
[94d84a0]663 list_initialize(&hr_volumes);
664
[b247c714]665 async_set_fallback_port_handler(hr_call_handler, NULL);
[94d84a0]666
667 rc = loc_server_register(NAME, &hr_srv);
668 if (rc != EOK) {
[d199a6f]669 HR_ERROR("failed registering server: %s", str_error(rc));
[94d84a0]670 return EEXIST;
671 }
672
[817cb83]673 rc = loc_service_register(hr_srv, SERVICE_NAME_HR, fallback_port_id,
674 &ctl_sid);
[94d84a0]675 if (rc != EOK) {
[d199a6f]676 HR_ERROR("failed registering service: %s", str_error(rc));
[94d84a0]677 return EEXIST;
678 }
679
[e2a8fd2]680 printf("%s: Trying automatic assembly.\n", NAME);
681 size_t assembled = 0;
682 (void)hr_util_try_assemble(NULL, &assembled);
683 printf("%s: Assembled %zu volume(s).\n", NAME, assembled);
684
[a056759]685 printf("%s: Accepting connections.\n", NAME);
[94d84a0]686 task_retval(0);
687 async_manager();
688
689 return 0;
690}
691
692/** @}
693 */
Note: See TracBrowser for help on using the repository browser.