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

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

hr: add initial RAID 5 with parity starting on extent 0 and data restart

  • Property mode set to 100644
File size: 11.0 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;
56fibril_mutex_t big_lock; /* for now */
57
58static fibril_mutex_t hr_volumes_lock;
59static list_t hr_volumes;
60
61static service_id_t ctl_sid;
62
63static hr_volume_t *hr_get_volume(service_id_t svc_id)
64{
65 log_msg(LOG_DEFAULT, LVL_DEBUG, "hr_get_volume(): (%" PRIun ")",
66 svc_id);
67
68 fibril_mutex_lock(&hr_volumes_lock);
69 list_foreach(hr_volumes, lvolumes, hr_volume_t, volume) {
70 if (volume->svc_id == svc_id) {
71 fibril_mutex_unlock(&hr_volumes_lock);
72 return volume;
73 }
74 }
75
76 fibril_mutex_unlock(&hr_volumes_lock);
77 return NULL;
78}
79
80static errno_t hr_remove_volume(service_id_t svc_id)
81{
82 log_msg(LOG_DEFAULT, LVL_DEBUG, "hr_remove_volume(): (%" PRIun ")",
83 svc_id);
84
85 fibril_mutex_lock(&hr_volumes_lock);
86 list_foreach(hr_volumes, lvolumes, hr_volume_t, volume) {
87 if (volume->svc_id == svc_id) {
88 hr_fini_devs(volume);
89 list_remove(&volume->lvolumes);
90 free(volume);
91 fibril_mutex_unlock(&hr_volumes_lock);
92 return EOK;
93 }
94 }
95
96 fibril_mutex_unlock(&hr_volumes_lock);
97 return ENOENT;
98}
99
100static void hr_create_srv(ipc_call_t *icall)
101{
102 log_msg(LOG_DEFAULT, LVL_NOTE, "hr_create_srv()");
103
104 errno_t rc;
105 size_t i, size;
106 hr_config_t *cfg;
107 hr_volume_t *new_volume;
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 async_answer_0(&call, rc);
132 async_answer_0(icall, rc);
133 return;
134 }
135
136 new_volume = calloc(1, sizeof(hr_volume_t));
137 if (new_volume == NULL) {
138 free(cfg);
139 async_answer_0(icall, ENOMEM);
140 return;
141 }
142
143 str_cpy(new_volume->devname, 32, cfg->devname);
144 for (i = 0; i < cfg->dev_no; i++)
145 new_volume->extents[i].svc_id = cfg->devs[i];
146 new_volume->level = cfg->level;
147 new_volume->dev_no = cfg->dev_no;
148
149 rc = hr_init_devs(new_volume);
150 if (rc != EOK) {
151 free(cfg);
152 async_answer_0(icall, rc);
153 return;
154 }
155
156 switch (new_volume->level) {
157 case hr_l_1:
158 new_volume->hr_ops.create = hr_raid1_create;
159 new_volume->hr_ops.init = hr_raid1_init;
160 break;
161 case hr_l_0:
162 new_volume->hr_ops.create = hr_raid0_create;
163 new_volume->hr_ops.init = hr_raid0_init;
164 break;
165 case hr_l_4:
166 new_volume->hr_ops.create = hr_raid4_create;
167 new_volume->hr_ops.init = hr_raid4_init;
168 break;
169 case hr_l_5:
170 new_volume->hr_ops.create = hr_raid5_create;
171 new_volume->hr_ops.init = hr_raid5_init;
172 break;
173 default:
174 log_msg(LOG_DEFAULT, LVL_ERROR,
175 "level %d not implemented yet", new_volume->level);
176 rc = EINVAL;
177 goto error;
178 }
179
180 new_volume->hr_ops.init(new_volume);
181 if (rc != EOK)
182 goto error;
183
184 rc = hr_write_meta_to_vol(new_volume);
185 if (rc != EOK)
186 goto error;
187
188 rc = new_volume->hr_ops.create(new_volume);
189 if (rc != EOK)
190 goto error;
191
192 fibril_mutex_lock(&hr_volumes_lock);
193 list_append(&new_volume->lvolumes, &hr_volumes);
194 fibril_mutex_unlock(&hr_volumes_lock);
195
196 log_msg(LOG_DEFAULT, LVL_NOTE, "created volume \"%s\" (%" PRIun ")",
197 new_volume->devname, new_volume->svc_id);
198
199 free(cfg);
200 async_answer_0(icall, rc);
201 return;
202error:
203 free(cfg);
204 hr_fini_devs(new_volume);
205 async_answer_0(icall, rc);
206}
207
208static void hr_assemble_srv(ipc_call_t *icall)
209{
210 log_msg(LOG_DEFAULT, LVL_NOTE, "hr_assemble_srv()");
211
212 errno_t rc;
213 size_t i, size;
214 hr_config_t *cfg;
215 hr_volume_t *new_volume;
216 ipc_call_t call;
217
218 if (!async_data_write_receive(&call, &size)) {
219 async_answer_0(&call, EREFUSED);
220 async_answer_0(icall, EREFUSED);
221 return;
222 }
223
224 if (size != sizeof(hr_config_t)) {
225 async_answer_0(&call, EINVAL);
226 async_answer_0(icall, EINVAL);
227 return;
228 }
229
230 cfg = calloc(1, sizeof(hr_config_t));
231 if (cfg == NULL) {
232 async_answer_0(&call, ENOMEM);
233 async_answer_0(icall, ENOMEM);
234 return;
235 }
236
237 rc = async_data_write_finalize(&call, cfg, size);
238 if (rc != EOK) {
239 async_answer_0(&call, rc);
240 async_answer_0(icall, rc);
241 return;
242 }
243
244 new_volume = calloc(1, sizeof(hr_volume_t));
245 if (new_volume == NULL) {
246 free(cfg);
247 async_answer_0(icall, ENOMEM);
248 return;
249 }
250
251 str_cpy(new_volume->devname, 32, cfg->devname);
252 for (i = 0; i < cfg->dev_no; i++)
253 new_volume->extents[i].svc_id = cfg->devs[i];
254 new_volume->dev_no = cfg->dev_no;
255
256 if (cfg->level != hr_l_empty)
257 log_msg(LOG_DEFAULT, LVL_WARN,
258 "level manually set when assembling, ingoring");
259
260 new_volume->level = hr_l_empty;
261
262 rc = hr_init_devs(new_volume);
263 if (rc != EOK) {
264 free(cfg);
265 async_answer_0(icall, rc);
266 return;
267 }
268
269 /* just bsize needed for reading metadata later */
270 rc = hr_check_devs(new_volume, NULL, &new_volume->bsize);
271 if (rc != EOK)
272 goto error;
273
274 rc = hr_get_vol_from_meta(cfg, new_volume);
275 if (rc != EOK)
276 goto error;
277
278 switch (new_volume->level) {
279 case hr_l_1:
280 new_volume->hr_ops.create = hr_raid1_create;
281 break;
282 case hr_l_0:
283 new_volume->hr_ops.create = hr_raid0_create;
284 break;
285 case hr_l_4:
286 new_volume->hr_ops.create = hr_raid4_create;
287 break;
288 case hr_l_5:
289 new_volume->hr_ops.create = hr_raid5_create;
290 break;
291 default:
292 log_msg(LOG_DEFAULT, LVL_ERROR,
293 "level %d not implemented yet", new_volume->level);
294 rc = EINVAL;
295 goto error;
296 }
297
298 rc = new_volume->hr_ops.create(new_volume);
299 if (rc != EOK)
300 goto error;
301
302 fibril_mutex_lock(&hr_volumes_lock);
303 list_append(&new_volume->lvolumes, &hr_volumes);
304 fibril_mutex_unlock(&hr_volumes_lock);
305
306 log_msg(LOG_DEFAULT, LVL_NOTE, "assembled volume \"%s\" (%" PRIun ")",
307 new_volume->devname, new_volume->svc_id);
308
309 free(cfg);
310 async_answer_0(icall, rc);
311 return;
312error:
313 free(cfg);
314 hr_fini_devs(new_volume);
315 async_answer_0(icall, rc);
316}
317
318static void hr_stop_srv(ipc_call_t *icall)
319{
320 log_msg(LOG_DEFAULT, LVL_NOTE, "hr_stop_srv()");
321
322 errno_t rc;
323 service_id_t svc_id;
324 hr_volume_t *vol;
325
326 svc_id = ipc_get_arg1(icall);
327
328 vol = hr_get_volume(svc_id);
329 if (vol == NULL) {
330 async_answer_0(icall, ENOENT);
331 return;
332 }
333
334 rc = hr_remove_volume(svc_id);
335 if (rc != EOK) {
336 async_answer_0(icall, rc);
337 return;
338 }
339
340 rc = loc_service_unregister(hr_srv, svc_id);
341
342 async_answer_0(icall, rc);
343}
344
345static void hr_print_status_srv(ipc_call_t *icall)
346{
347 log_msg(LOG_DEFAULT, LVL_NOTE, "hr_status_srv()");
348
349 errno_t rc;
350 size_t vol_cnt = 0;
351 hr_vol_info_t info;
352 ipc_call_t call;
353 size_t size;
354
355 fibril_mutex_lock(&hr_volumes_lock);
356
357 vol_cnt = list_count(&hr_volumes);
358
359 if (!async_data_read_receive(&call, &size)) {
360 rc = EREFUSED;
361 goto error;
362 }
363
364 if (size != sizeof(size_t)) {
365 rc = EINVAL;
366 goto error;
367 }
368
369 rc = async_data_read_finalize(&call, &vol_cnt, size);
370 if (rc != EOK)
371 goto error;
372
373 list_foreach(hr_volumes, lvolumes, hr_volume_t, volume) {
374 memcpy(info.extents, volume->extents,
375 sizeof(hr_extent_t) * HR_MAXDEVS);
376 info.svc_id = volume->svc_id;
377 info.extent_no = volume->dev_no;
378 info.level = volume->level;
379 /* print usable number of blocks */
380 info.nblocks = volume->data_blkno;
381 info.strip_size = volume->strip_size;
382 info.bsize = volume->bsize;
383
384 if (!async_data_read_receive(&call, &size)) {
385 rc = EREFUSED;
386 goto error;
387 }
388
389 if (size != sizeof(hr_vol_info_t)) {
390 rc = EINVAL;
391 goto error;
392 }
393
394 rc = async_data_read_finalize(&call, &info, size);
395 if (rc != EOK)
396 goto error;
397 }
398
399 fibril_mutex_unlock(&hr_volumes_lock);
400 async_answer_0(icall, EOK);
401 return;
402error:
403 fibril_mutex_unlock(&hr_volumes_lock);
404 async_answer_0(&call, rc);
405 async_answer_0(icall, rc);
406}
407
408static void hr_ctl_conn(ipc_call_t *icall, void *arg)
409{
410 log_msg(LOG_DEFAULT, LVL_NOTE, "hr_ctl_conn()");
411
412 async_accept_0(icall);
413
414 while (true) {
415 ipc_call_t call;
416 async_get_call(&call);
417 sysarg_t method = ipc_get_imethod(&call);
418
419 if (!method) {
420 async_answer_0(&call, EOK);
421 return;
422 }
423
424 switch (method) {
425 case HR_CREATE:
426 hr_create_srv(&call);
427 break;
428 case HR_ASSEMBLE:
429 hr_assemble_srv(&call);
430 break;
431 case HR_STOP:
432 hr_stop_srv(&call);
433 break;
434 case HR_STATUS:
435 hr_print_status_srv(&call);
436 break;
437 default:
438 async_answer_0(&call, EINVAL);
439 }
440 }
441}
442
443static void hr_client_conn(ipc_call_t *icall, void *arg)
444{
445 log_msg(LOG_DEFAULT, LVL_NOTE, "hr_client_conn()");
446
447 hr_volume_t *vol;
448
449 service_id_t svc_id = ipc_get_arg2(icall);
450
451 if (svc_id == ctl_sid) {
452 hr_ctl_conn(icall, arg);
453 } else {
454 log_msg(LOG_DEFAULT, LVL_NOTE, "bd_conn()");
455 vol = hr_get_volume(svc_id);
456 if (vol == NULL)
457 async_answer_0(icall, EINVAL);
458 bd_conn(icall, &vol->hr_bds);
459 }
460}
461
462int main(int argc, char **argv)
463{
464 errno_t rc;
465
466 printf("%s: HelenRAID server\n", NAME);
467
468 rc = log_init(NAME);
469 if (rc != EOK) {
470 printf("%s: failed to initialize logging\n", NAME);
471 return 1;
472 }
473
474 fibril_mutex_initialize(&big_lock);
475
476 fibril_mutex_initialize(&hr_volumes_lock);
477 list_initialize(&hr_volumes);
478
479 async_set_fallback_port_handler(hr_client_conn, NULL);
480
481 rc = loc_server_register(NAME, &hr_srv);
482 if (rc != EOK) {
483 log_msg(LOG_DEFAULT, LVL_ERROR,
484 "failed registering server: %s", str_error(rc));
485 return EEXIST;
486 }
487
488 rc = loc_service_register(hr_srv, SERVICE_NAME_HR, &ctl_sid);
489 if (rc != EOK) {
490 log_msg(LOG_DEFAULT, LVL_ERROR,
491 "failed registering service: %s", str_error(rc));
492 return EEXIST;
493 }
494
495 printf("%s: accepting connections\n", NAME);
496 task_retval(0);
497 async_manager();
498
499 return 0;
500}
501
502/** @}
503 */
Note: See TracBrowser for help on using the repository browser.