source: mainline/uspace/srv/bd/hr/hr.c@ 8137d36

Last change on this file since 8137d36 was 37a9c1e, checked in by Miroslav Cimerman <mc@…>, 10 months ago

hr: hr_volume_t: rename RLQ → layout

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