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

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

hr: add option to silently fail an extent

  • Property mode set to 100644
File size: 9.9 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 log_msg(LOG_DEFAULT, LVL_DEBUG, "hr_get_volume(): (%" PRIun ")",
65 svc_id);
66
67 fibril_mutex_lock(&hr_volumes_lock);
68 list_foreach(hr_volumes, lvolumes, hr_volume_t, volume) {
69 if (volume->svc_id == svc_id) {
70 fibril_mutex_unlock(&hr_volumes_lock);
71 return volume;
72 }
73 }
74
75 fibril_mutex_unlock(&hr_volumes_lock);
76 return NULL;
77}
78
79static errno_t hr_remove_volume(service_id_t svc_id)
80{
81 log_msg(LOG_DEFAULT, LVL_DEBUG, "hr_remove_volume(): (%" PRIun ")",
82 svc_id);
83
84 fibril_mutex_lock(&hr_volumes_lock);
85 list_foreach(hr_volumes, lvolumes, hr_volume_t, volume) {
86 if (volume->svc_id == svc_id) {
87 hr_fini_devs(volume);
88 list_remove(&volume->lvolumes);
89 free(volume);
90 fibril_mutex_unlock(&hr_volumes_lock);
91 return EOK;
92 }
93 }
94
95 fibril_mutex_unlock(&hr_volumes_lock);
96 return ENOENT;
97}
98
99static void hr_create_srv(ipc_call_t *icall, bool assemble)
100{
101 log_msg(LOG_DEFAULT, LVL_NOTE, "hr_create_srv()");
102
103 errno_t rc;
104 size_t i, size;
105 hr_config_t *cfg;
106 hr_volume_t *new_volume;
107 ipc_call_t call;
108
109 if (!async_data_write_receive(&call, &size)) {
110 async_answer_0(&call, EREFUSED);
111 async_answer_0(icall, EREFUSED);
112 return;
113 }
114
115 if (size != sizeof(hr_config_t)) {
116 async_answer_0(&call, EINVAL);
117 async_answer_0(icall, EINVAL);
118 return;
119 }
120
121 cfg = calloc(1, sizeof(hr_config_t));
122 if (cfg == NULL) {
123 async_answer_0(&call, ENOMEM);
124 async_answer_0(icall, ENOMEM);
125 return;
126 }
127
128 rc = async_data_write_finalize(&call, cfg, size);
129 if (rc != EOK) {
130 free(cfg);
131 async_answer_0(&call, rc);
132 async_answer_0(icall, rc);
133 return;
134 }
135
136 /*
137 * If there was a missing device provided
138 * for creation of a new array, abort
139 */
140 if (!assemble) {
141 for (i = 0; i < cfg->dev_no; i++) {
142 if (cfg->devs[i] == 0) {
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 log_msg(LOG_DEFAULT, LVL_WARN,
166 "level manually set when assembling, ingoring");
167 new_volume->level = HR_LVL_UNKNOWN;
168 }
169
170 rc = hr_init_devs(new_volume);
171 if (rc != EOK) {
172 free(cfg);
173 free(new_volume);
174 async_answer_0(icall, rc);
175 return;
176 }
177
178 if (assemble) {
179 /* just bsize needed for reading metadata later */
180 rc = hr_check_devs(new_volume, NULL, &new_volume->bsize);
181 if (rc != EOK)
182 goto error;
183
184 rc = hr_fill_vol_from_meta(new_volume);
185 if (rc != EOK)
186 goto error;
187 }
188
189 switch (new_volume->level) {
190 case HR_LVL_1:
191 new_volume->hr_ops.create = hr_raid1_create;
192 new_volume->hr_ops.init = hr_raid1_init;
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 break;
198 case HR_LVL_4:
199 new_volume->hr_ops.create = hr_raid4_create;
200 new_volume->hr_ops.init = hr_raid4_init;
201 break;
202 case HR_LVL_5:
203 new_volume->hr_ops.create = hr_raid5_create;
204 new_volume->hr_ops.init = hr_raid5_init;
205 break;
206 default:
207 log_msg(LOG_DEFAULT, LVL_ERROR,
208 "level %d not implemented yet", new_volume->level);
209 rc = EINVAL;
210 goto error;
211 }
212
213 if (!assemble) {
214 new_volume->hr_ops.init(new_volume);
215 if (rc != EOK)
216 goto error;
217
218 rc = hr_write_meta_to_vol(new_volume);
219 if (rc != EOK)
220 goto error;
221 }
222
223 fibril_mutex_initialize(&new_volume->lock);
224
225 rc = new_volume->hr_ops.create(new_volume);
226 if (rc != EOK)
227 goto error;
228
229 fibril_mutex_lock(&hr_volumes_lock);
230 list_append(&new_volume->lvolumes, &hr_volumes);
231 fibril_mutex_unlock(&hr_volumes_lock);
232
233 if (assemble) {
234 log_msg(LOG_DEFAULT, LVL_NOTE,
235 "assembled volume \"%s\" (%" PRIun ")",
236 new_volume->devname, new_volume->svc_id);
237 } else {
238 log_msg(LOG_DEFAULT, LVL_NOTE,
239 "created volume \"%s\" (%" PRIun ")",
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 log_msg(LOG_DEFAULT, LVL_NOTE, "hr_stop_srv()");
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 async_answer_0(icall, rc);
285}
286
287static void hr_print_status_srv(ipc_call_t *icall)
288{
289 log_msg(LOG_DEFAULT, LVL_NOTE, "hr_status_srv()");
290
291 errno_t rc;
292 size_t vol_cnt = 0;
293 hr_vol_info_t info;
294 ipc_call_t call;
295 size_t size;
296
297 fibril_mutex_lock(&hr_volumes_lock);
298
299 vol_cnt = list_count(&hr_volumes);
300
301 if (!async_data_read_receive(&call, &size)) {
302 rc = EREFUSED;
303 goto error;
304 }
305
306 if (size != sizeof(size_t)) {
307 rc = EINVAL;
308 goto error;
309 }
310
311 rc = async_data_read_finalize(&call, &vol_cnt, size);
312 if (rc != EOK)
313 goto error;
314
315 list_foreach(hr_volumes, lvolumes, hr_volume_t, volume) {
316 memcpy(info.extents, volume->extents,
317 sizeof(hr_extent_t) * HR_MAXDEVS);
318 info.svc_id = volume->svc_id;
319 info.extent_no = volume->dev_no;
320 info.level = volume->level;
321 /* print usable number of blocks */
322 info.nblocks = volume->data_blkno;
323 info.strip_size = volume->strip_size;
324 info.bsize = volume->bsize;
325 info.status = volume->status;
326
327 if (!async_data_read_receive(&call, &size)) {
328 rc = EREFUSED;
329 goto error;
330 }
331
332 if (size != sizeof(hr_vol_info_t)) {
333 rc = EINVAL;
334 goto error;
335 }
336
337 rc = async_data_read_finalize(&call, &info, size);
338 if (rc != EOK)
339 goto error;
340 }
341
342 fibril_mutex_unlock(&hr_volumes_lock);
343 async_answer_0(icall, EOK);
344 return;
345error:
346 fibril_mutex_unlock(&hr_volumes_lock);
347 async_answer_0(&call, rc);
348 async_answer_0(icall, rc);
349}
350
351static void hr_ctl_conn(ipc_call_t *icall, void *arg)
352{
353 log_msg(LOG_DEFAULT, LVL_NOTE, "hr_ctl_conn()");
354
355 async_accept_0(icall);
356
357 while (true) {
358 ipc_call_t call;
359 async_get_call(&call);
360 sysarg_t method = ipc_get_imethod(&call);
361
362 if (!method) {
363 async_answer_0(&call, EOK);
364 return;
365 }
366
367 switch (method) {
368 case HR_CREATE:
369 hr_create_srv(&call, false);
370 break;
371 case HR_ASSEMBLE:
372 hr_create_srv(&call, true);
373 break;
374 case HR_STOP:
375 hr_stop_srv(&call);
376 break;
377 case HR_STATUS:
378 hr_print_status_srv(&call);
379 break;
380 default:
381 async_answer_0(&call, EINVAL);
382 }
383 }
384}
385
386static void hr_client_conn(ipc_call_t *icall, void *arg)
387{
388 log_msg(LOG_DEFAULT, LVL_NOTE, "hr_client_conn()");
389
390 hr_volume_t *vol;
391
392 service_id_t svc_id = ipc_get_arg2(icall);
393
394 if (svc_id == ctl_sid) {
395 hr_ctl_conn(icall, arg);
396 } else {
397 log_msg(LOG_DEFAULT, LVL_NOTE, "bd_conn()");
398 vol = hr_get_volume(svc_id);
399 if (vol == NULL)
400 async_answer_0(icall, EINVAL);
401 bd_conn(icall, &vol->hr_bds);
402 }
403}
404
405int main(int argc, char **argv)
406{
407 errno_t rc;
408
409 printf("%s: HelenRAID server\n", NAME);
410
411 rc = log_init(NAME);
412 if (rc != EOK) {
413 printf("%s: failed to initialize logging\n", NAME);
414 return 1;
415 }
416
417 fibril_mutex_initialize(&hr_volumes_lock);
418 list_initialize(&hr_volumes);
419
420 async_set_fallback_port_handler(hr_client_conn, NULL);
421
422 rc = loc_server_register(NAME, &hr_srv);
423 if (rc != EOK) {
424 log_msg(LOG_DEFAULT, LVL_ERROR,
425 "failed registering server: %s", str_error(rc));
426 return EEXIST;
427 }
428
429 rc = loc_service_register(hr_srv, SERVICE_NAME_HR, &ctl_sid);
430 if (rc != EOK) {
431 log_msg(LOG_DEFAULT, LVL_ERROR,
432 "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.