source: mainline/uspace/srv/bd/hr/hr.c@ 06f2762

Last change on this file since 06f2762 was 7b359f5, checked in by Miroslav Cimerman <mc@…>, 9 months ago

hr: status/state event function for each RAID

  • Property mode set to 100644
File size: 9.8 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->dev_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 new_volume->hr_ops.create = hr_raid1_create;
191 new_volume->hr_ops.init = hr_raid1_init;
192 new_volume->hr_ops.status_event = hr_raid1_status_event;
193 break;
194 case HR_LVL_0:
195 new_volume->hr_ops.create = hr_raid0_create;
196 new_volume->hr_ops.init = hr_raid0_init;
197 new_volume->hr_ops.status_event = hr_raid0_status_event;
198 break;
199 case HR_LVL_4:
200 new_volume->hr_ops.create = hr_raid4_create;
201 new_volume->hr_ops.init = hr_raid4_init;
202 new_volume->hr_ops.status_event = hr_raid4_status_event;
203 break;
204 case HR_LVL_5:
205 new_volume->hr_ops.create = hr_raid5_create;
206 new_volume->hr_ops.init = hr_raid5_init;
207 new_volume->hr_ops.status_event = hr_raid5_status_event;
208 break;
209 default:
210 HR_ERROR("unkown level: %d, aborting\n", new_volume->level);
211 rc = EINVAL;
212 goto error;
213 }
214
215 if (!assemble) {
216 new_volume->hr_ops.init(new_volume);
217 if (rc != EOK)
218 goto error;
219
220 rc = hr_write_meta_to_vol(new_volume);
221 if (rc != EOK)
222 goto error;
223 }
224
225 fibril_mutex_initialize(&new_volume->lock);
226
227 rc = new_volume->hr_ops.create(new_volume);
228 if (rc != EOK)
229 goto error;
230
231 fibril_mutex_lock(&hr_volumes_lock);
232 list_append(&new_volume->lvolumes, &hr_volumes);
233 fibril_mutex_unlock(&hr_volumes_lock);
234
235 if (assemble) {
236 HR_DEBUG("assembled volume \"%s\" (%" PRIun ")\n",
237 new_volume->devname, new_volume->svc_id);
238 } else {
239 HR_DEBUG("created volume \"%s\" (%" PRIun ")\n",
240 new_volume->devname, new_volume->svc_id);
241 }
242
243 free(cfg);
244 async_answer_0(icall, rc);
245 return;
246error:
247 free(cfg);
248 hr_fini_devs(new_volume);
249 free(new_volume);
250 async_answer_0(icall, rc);
251}
252
253static void hr_stop_srv(ipc_call_t *icall)
254{
255 HR_DEBUG("hr_stop_srv()\n");
256
257 errno_t rc = EOK;
258 service_id_t svc_id;
259 long fail_extent;
260 hr_volume_t *vol;
261
262 svc_id = ipc_get_arg1(icall);
263 fail_extent = (long) ipc_get_arg2(icall);
264
265 vol = hr_get_volume(svc_id);
266 if (vol == NULL) {
267 async_answer_0(icall, ENOENT);
268 return;
269 }
270
271 if (fail_extent == -1) {
272 rc = hr_remove_volume(svc_id);
273 if (rc != EOK) {
274 async_answer_0(icall, rc);
275 return;
276 }
277 rc = loc_service_unregister(hr_srv, svc_id);
278 } else {
279 /* fibril safe for now */
280 fibril_mutex_lock(&vol->lock);
281 hr_update_ext_status(vol, fail_extent, HR_EXT_FAILED);
282 fibril_mutex_unlock(&vol->lock);
283
284 vol->hr_ops.status_event(vol);
285 }
286 async_answer_0(icall, rc);
287}
288
289static void hr_print_status_srv(ipc_call_t *icall)
290{
291 HR_DEBUG("hr_status_srv()\n");
292
293 errno_t rc;
294 size_t vol_cnt = 0;
295 hr_vol_info_t info;
296 ipc_call_t call;
297 size_t size;
298
299 fibril_mutex_lock(&hr_volumes_lock);
300
301 vol_cnt = list_count(&hr_volumes);
302
303 if (!async_data_read_receive(&call, &size)) {
304 rc = EREFUSED;
305 goto error;
306 }
307
308 if (size != sizeof(size_t)) {
309 rc = EINVAL;
310 goto error;
311 }
312
313 rc = async_data_read_finalize(&call, &vol_cnt, size);
314 if (rc != EOK)
315 goto error;
316
317 list_foreach(hr_volumes, lvolumes, hr_volume_t, vol) {
318 memcpy(info.extents, vol->extents,
319 sizeof(hr_extent_t) * HR_MAX_EXTENTS);
320 info.svc_id = vol->svc_id;
321 info.extent_no = vol->dev_no;
322 info.level = vol->level;
323 /* print usable number of blocks */
324 info.nblocks = vol->data_blkno;
325 info.strip_size = vol->strip_size;
326 info.bsize = vol->bsize;
327 info.status = vol->status;
328
329 if (!async_data_read_receive(&call, &size)) {
330 rc = EREFUSED;
331 goto error;
332 }
333
334 if (size != sizeof(hr_vol_info_t)) {
335 rc = EINVAL;
336 goto error;
337 }
338
339 rc = async_data_read_finalize(&call, &info, size);
340 if (rc != EOK)
341 goto error;
342 }
343
344 fibril_mutex_unlock(&hr_volumes_lock);
345 async_answer_0(icall, EOK);
346 return;
347error:
348 fibril_mutex_unlock(&hr_volumes_lock);
349 async_answer_0(&call, rc);
350 async_answer_0(icall, rc);
351}
352
353static void hr_ctl_conn(ipc_call_t *icall, void *arg)
354{
355 HR_DEBUG("hr_ctl_conn()\n");
356
357 async_accept_0(icall);
358
359 while (true) {
360 ipc_call_t call;
361 async_get_call(&call);
362 sysarg_t method = ipc_get_imethod(&call);
363
364 if (!method) {
365 async_answer_0(&call, EOK);
366 return;
367 }
368
369 switch (method) {
370 case HR_CREATE:
371 hr_create_srv(&call, false);
372 break;
373 case HR_ASSEMBLE:
374 hr_create_srv(&call, true);
375 break;
376 case HR_STOP:
377 hr_stop_srv(&call);
378 break;
379 case HR_STATUS:
380 hr_print_status_srv(&call);
381 break;
382 default:
383 async_answer_0(&call, EINVAL);
384 }
385 }
386}
387
388static void hr_client_conn(ipc_call_t *icall, void *arg)
389{
390 HR_DEBUG("hr_client_conn()\n");
391
392 hr_volume_t *vol;
393
394 service_id_t svc_id = ipc_get_arg2(icall);
395
396 if (svc_id == ctl_sid) {
397 hr_ctl_conn(icall, arg);
398 } else {
399 HR_DEBUG("bd_conn()\n");
400 vol = hr_get_volume(svc_id);
401 if (vol == NULL)
402 async_answer_0(icall, EINVAL);
403 bd_conn(icall, &vol->hr_bds);
404 }
405}
406
407int main(int argc, char **argv)
408{
409 errno_t rc;
410
411 printf("%s: HelenRAID server\n", NAME);
412
413 rc = log_init(NAME);
414 if (rc != EOK) {
415 printf("%s: failed to initialize logging\n", NAME);
416 return 1;
417 }
418
419 fibril_mutex_initialize(&hr_volumes_lock);
420 list_initialize(&hr_volumes);
421
422 async_set_fallback_port_handler(hr_client_conn, NULL);
423
424 rc = loc_server_register(NAME, &hr_srv);
425 if (rc != EOK) {
426 HR_ERROR("failed registering server: %s", str_error(rc));
427 return EEXIST;
428 }
429
430 rc = loc_service_register(hr_srv, SERVICE_NAME_HR, &ctl_sid);
431 if (rc != EOK) {
432 HR_ERROR("failed registering service: %s", str_error(rc));
433 return EEXIST;
434 }
435
436 printf("%s: accepting connections\n", NAME);
437 task_retval(0);
438 async_manager();
439
440 return 0;
441}
442
443/** @}
444 */
Note: See TracBrowser for help on using the repository browser.