source: mainline/uspace/srv/bd/hr/hr.c@ 25830c2

Last change on this file since 25830c2 was ba65caf5, checked in by Miroslav Cimerman <mc@…>, 4 weeks ago

hr: hr.c: potentially answer EBUSY on HR_STOP_ALL

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