[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] | 56 | static void hr_assemble_srv(ipc_call_t *);
|
---|
| 57 | static void hr_auto_assemble_srv(ipc_call_t *);
|
---|
| 58 | static void hr_stop_srv(ipc_call_t *);
|
---|
[d1d355f] | 59 | static void hr_stop_all_srv(ipc_call_t *);
|
---|
[6d0fc11] | 60 | static void hr_add_hotspare_srv(ipc_call_t *);
|
---|
[56602e0] | 61 | static void hr_print_state_srv(ipc_call_t *);
|
---|
[31eb568] | 62 | static void hr_ctl_conn(ipc_call_t *);
|
---|
[6d0fc11] | 63 | static void hr_client_conn(ipc_call_t *, void *);
|
---|
| 64 |
|
---|
[94d84a0] | 65 | loc_srv_t *hr_srv;
|
---|
[8b51009] | 66 | list_t hr_volumes;
|
---|
| 67 | fibril_rwlock_t hr_volumes_lock;
|
---|
[94d84a0] | 68 |
|
---|
| 69 | static 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] | 78 | static 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 |
|
---|
| 115 | /*
|
---|
| 116 | * If there was a missing device provided
|
---|
[af73327a] | 117 | * for creation of a new volume, abort
|
---|
[6d0fc11] | 118 | */
|
---|
| 119 | for (i = 0; i < cfg->dev_no; i++) {
|
---|
| 120 | if (cfg->devs[i] == 0) {
|
---|
| 121 | /*
|
---|
| 122 | * XXX: own error codes, no need to log this...
|
---|
| 123 | * its user error not service error
|
---|
| 124 | */
|
---|
[af73327a] | 125 | HR_ERROR("missing device provided for volume "
|
---|
[6d0fc11] | 126 | "creation, aborting");
|
---|
| 127 | free(cfg);
|
---|
| 128 | async_answer_0(icall, EINVAL);
|
---|
| 129 | return;
|
---|
| 130 | }
|
---|
| 131 | }
|
---|
| 132 |
|
---|
[50603405] | 133 | rc = hr_create_vol_struct(&vol, cfg->level, cfg->devname,
|
---|
| 134 | HR_METADATA_NATIVE);
|
---|
[6d0fc11] | 135 | if (rc != EOK) {
|
---|
| 136 | free(cfg);
|
---|
| 137 | async_answer_0(icall, rc);
|
---|
| 138 | return;
|
---|
| 139 | }
|
---|
| 140 |
|
---|
[50603405] | 141 | rc = hr_init_extents_from_cfg(vol, cfg);
|
---|
[baa4929] | 142 | if (rc != EOK)
|
---|
| 143 | goto error;
|
---|
[6d0fc11] | 144 |
|
---|
[50603405] | 145 | vol->hr_ops.init(vol);
|
---|
[d082801] | 146 | if (rc != EOK)
|
---|
| 147 | goto error;
|
---|
| 148 |
|
---|
[50603405] | 149 | rc = vol->meta_ops->init_vol2meta(vol, vol->in_mem_md);
|
---|
[0277ec2] | 150 | if (rc != EOK)
|
---|
| 151 | goto error;
|
---|
| 152 |
|
---|
[50603405] | 153 | rc = vol->hr_ops.create(vol);
|
---|
[d082801] | 154 | if (rc != EOK)
|
---|
| 155 | goto error;
|
---|
| 156 |
|
---|
[50603405] | 157 | rc = vol->meta_ops->save(vol, WITH_STATE_CALLBACK);
|
---|
[6d0fc11] | 158 | if (rc != EOK)
|
---|
| 159 | goto error;
|
---|
| 160 |
|
---|
[50603405] | 161 | rc = hr_register_volume(vol);
|
---|
[6d0fc11] | 162 | if (rc != EOK)
|
---|
| 163 | goto error;
|
---|
| 164 |
|
---|
| 165 | fibril_rwlock_write_lock(&hr_volumes_lock);
|
---|
[50603405] | 166 | list_append(&vol->lvolumes, &hr_volumes);
|
---|
[6d0fc11] | 167 | fibril_rwlock_write_unlock(&hr_volumes_lock);
|
---|
| 168 |
|
---|
[d1d355f] | 169 | HR_NOTE("created volume \"%s\"\n", vol->devname);
|
---|
[6d0fc11] | 170 |
|
---|
| 171 | free(cfg);
|
---|
| 172 | async_answer_0(icall, rc);
|
---|
[d082801] | 173 | return;
|
---|
| 174 | error:
|
---|
[6d0fc11] | 175 | free(cfg);
|
---|
[50603405] | 176 | hr_destroy_vol_struct(vol);
|
---|
[d082801] | 177 | async_answer_0(icall, rc);
|
---|
| 178 | }
|
---|
| 179 |
|
---|
[31eb568] | 180 | /** Manual volume assembly (server).
|
---|
| 181 | *
|
---|
| 182 | * Tries to assemble a volume from devices in hr_config_t and
|
---|
| 183 | * sends the number of successful volumes assembled back to the
|
---|
| 184 | * client.
|
---|
| 185 | *
|
---|
| 186 | * @param icall hr_config_t
|
---|
| 187 | */
|
---|
[d082801] | 188 | static void hr_assemble_srv(ipc_call_t *icall)
|
---|
| 189 | {
|
---|
| 190 | HR_DEBUG("%s()", __func__);
|
---|
| 191 |
|
---|
| 192 | errno_t rc;
|
---|
| 193 | size_t size, assembled_cnt;
|
---|
| 194 | hr_config_t *cfg;
|
---|
| 195 | ipc_call_t call;
|
---|
| 196 |
|
---|
| 197 | if (!async_data_write_receive(&call, &size)) {
|
---|
| 198 | async_answer_0(&call, EREFUSED);
|
---|
| 199 | async_answer_0(icall, EREFUSED);
|
---|
[8b51009] | 200 | return;
|
---|
| 201 | }
|
---|
[a19d7fc4] | 202 |
|
---|
[d082801] | 203 | if (size != sizeof(hr_config_t)) {
|
---|
| 204 | async_answer_0(&call, EINVAL);
|
---|
| 205 | async_answer_0(icall, EINVAL);
|
---|
| 206 | return;
|
---|
| 207 | }
|
---|
| 208 |
|
---|
| 209 | cfg = calloc(1, sizeof(hr_config_t));
|
---|
| 210 | if (cfg == NULL) {
|
---|
| 211 | async_answer_0(&call, ENOMEM);
|
---|
| 212 | async_answer_0(icall, ENOMEM);
|
---|
| 213 | return;
|
---|
| 214 | }
|
---|
| 215 |
|
---|
| 216 | rc = async_data_write_finalize(&call, cfg, size);
|
---|
| 217 | if (rc != EOK)
|
---|
| 218 | goto error;
|
---|
| 219 |
|
---|
| 220 | if (!async_data_read_receive(&call, &size)) {
|
---|
| 221 | async_answer_0(icall, EREFUSED);
|
---|
[8b51009] | 222 | return;
|
---|
[a19d7fc4] | 223 | }
|
---|
| 224 |
|
---|
[d082801] | 225 | if (size != sizeof(size_t)) {
|
---|
| 226 | async_answer_0(icall, EINVAL);
|
---|
| 227 | return;
|
---|
| 228 | }
|
---|
| 229 |
|
---|
| 230 | rc = hr_util_try_assemble(cfg, &assembled_cnt);
|
---|
| 231 | if (rc != EOK)
|
---|
| 232 | goto error;
|
---|
| 233 |
|
---|
| 234 | rc = async_data_read_finalize(&call, &assembled_cnt, size);
|
---|
| 235 | if (rc != EOK)
|
---|
| 236 | goto error;
|
---|
| 237 |
|
---|
| 238 | free(cfg);
|
---|
[8b51009] | 239 | async_answer_0(icall, EOK);
|
---|
[d082801] | 240 | return;
|
---|
| 241 | error:
|
---|
| 242 | free(cfg);
|
---|
| 243 | async_answer_0(&call, rc);
|
---|
| 244 | async_answer_0(icall, rc);
|
---|
[a19d7fc4] | 245 | }
|
---|
| 246 |
|
---|
[31eb568] | 247 | /** Automatic volume assembly (server).
|
---|
| 248 | *
|
---|
| 249 | * Tries to assemble a volume from devices in disk location
|
---|
| 250 | * category and sends the number of successful volumes assembled
|
---|
| 251 | * back to client.
|
---|
| 252 | */
|
---|
[6d0fc11] | 253 | static void hr_auto_assemble_srv(ipc_call_t *icall)
|
---|
[94d84a0] | 254 | {
|
---|
[a57dde4] | 255 | HR_DEBUG("%s()", __func__);
|
---|
[94d84a0] | 256 |
|
---|
| 257 | errno_t rc;
|
---|
[6d0fc11] | 258 | size_t size;
|
---|
| 259 | size_t assembled_cnt = 0;
|
---|
[68e357e] | 260 | ipc_call_t call;
|
---|
[94d84a0] | 261 |
|
---|
[6d0fc11] | 262 | if (!async_data_read_receive(&call, &size)) {
|
---|
[68e357e] | 263 | async_answer_0(icall, EREFUSED);
|
---|
[94d84a0] | 264 | return;
|
---|
| 265 | }
|
---|
| 266 |
|
---|
[6d0fc11] | 267 | if (size != sizeof(size_t)) {
|
---|
[68e357e] | 268 | async_answer_0(&call, EINVAL);
|
---|
| 269 | async_answer_0(icall, EINVAL);
|
---|
[94d84a0] | 270 | return;
|
---|
| 271 | }
|
---|
| 272 |
|
---|
[6d0fc11] | 273 | rc = hr_util_try_assemble(NULL, &assembled_cnt);
|
---|
[b0f1366] | 274 | if (rc != EOK)
|
---|
| 275 | goto error;
|
---|
| 276 |
|
---|
[6d0fc11] | 277 | rc = async_data_read_finalize(&call, &assembled_cnt, size);
|
---|
[8a65373] | 278 | if (rc != EOK)
|
---|
| 279 | goto error;
|
---|
| 280 |
|
---|
[6d0fc11] | 281 | async_answer_0(icall, EOK);
|
---|
[b0f1366] | 282 | return;
|
---|
| 283 | error:
|
---|
[6d0fc11] | 284 | async_answer_0(&call, rc);
|
---|
[b0f1366] | 285 | async_answer_0(icall, rc);
|
---|
[94d84a0] | 286 | }
|
---|
| 287 |
|
---|
[31eb568] | 288 | /** Volume deactivation (server).
|
---|
| 289 | *
|
---|
| 290 | * Deactivates/detaches specified volume.
|
---|
| 291 | */
|
---|
[a19d7fc4] | 292 | static void hr_stop_srv(ipc_call_t *icall)
|
---|
| 293 | {
|
---|
[a57dde4] | 294 | HR_DEBUG("%s()", __func__);
|
---|
[a19d7fc4] | 295 |
|
---|
[cf28ffd3] | 296 | errno_t rc = EOK;
|
---|
[a19d7fc4] | 297 | service_id_t svc_id;
|
---|
| 298 | hr_volume_t *vol;
|
---|
| 299 |
|
---|
| 300 | svc_id = ipc_get_arg1(icall);
|
---|
| 301 |
|
---|
| 302 | vol = hr_get_volume(svc_id);
|
---|
| 303 | if (vol == NULL) {
|
---|
| 304 | async_answer_0(icall, ENOENT);
|
---|
| 305 | return;
|
---|
| 306 | }
|
---|
| 307 |
|
---|
[d1d355f] | 308 | rc = hr_remove_volume(vol);
|
---|
| 309 |
|
---|
| 310 | async_answer_0(icall, rc);
|
---|
| 311 | }
|
---|
| 312 |
|
---|
[31eb568] | 313 | /** Automatic volume deactivation (server).
|
---|
| 314 | *
|
---|
| 315 | * Tries to deactivate/detach all volumes.
|
---|
| 316 | */
|
---|
[d1d355f] | 317 | static void hr_stop_all_srv(ipc_call_t *icall)
|
---|
| 318 | {
|
---|
| 319 | HR_DEBUG("%s()", __func__);
|
---|
| 320 |
|
---|
| 321 | hr_volume_t *vol;
|
---|
| 322 | errno_t rc = EOK;
|
---|
| 323 |
|
---|
| 324 | while (true) {
|
---|
| 325 | fibril_rwlock_write_lock(&hr_volumes_lock);
|
---|
| 326 | if (list_empty(&hr_volumes)) {
|
---|
| 327 | fibril_rwlock_write_unlock(&hr_volumes_lock);
|
---|
| 328 | break;
|
---|
[cf28ffd3] | 329 | }
|
---|
[401b9e42] | 330 |
|
---|
[d1d355f] | 331 | vol = list_pop(&hr_volumes, hr_volume_t, lvolumes);
|
---|
[401b9e42] | 332 |
|
---|
[d1d355f] | 333 | fibril_rwlock_write_unlock(&hr_volumes_lock);
|
---|
[7b359f5] | 334 |
|
---|
[d1d355f] | 335 | rc = hr_remove_volume(vol);
|
---|
| 336 | if (rc != EOK)
|
---|
| 337 | break;
|
---|
[a19d7fc4] | 338 | }
|
---|
[d1d355f] | 339 |
|
---|
[a19d7fc4] | 340 | async_answer_0(icall, rc);
|
---|
| 341 | }
|
---|
| 342 |
|
---|
[31eb568] | 343 | /** Simulate volume extent failure (server).
|
---|
| 344 | *
|
---|
| 345 | * Changes the specified extent's state to FAULTY.
|
---|
| 346 | * Other extents' metadata are marked as dirty, therefore
|
---|
| 347 | * it effectively invalides the specified extent as well
|
---|
| 348 | * for further uses.
|
---|
| 349 | */
|
---|
[d1d355f] | 350 | static void hr_fail_extent_srv(ipc_call_t *icall)
|
---|
| 351 | {
|
---|
| 352 | HR_DEBUG("%s()", __func__);
|
---|
| 353 |
|
---|
| 354 | service_id_t svc_id;
|
---|
| 355 | size_t fail_extent;
|
---|
| 356 | hr_volume_t *vol;
|
---|
| 357 |
|
---|
| 358 | svc_id = (service_id_t)ipc_get_arg1(icall);
|
---|
| 359 | fail_extent = (size_t)ipc_get_arg2(icall);
|
---|
| 360 |
|
---|
| 361 | vol = hr_get_volume(svc_id);
|
---|
| 362 | if (vol == NULL) {
|
---|
| 363 | async_answer_0(icall, ENOENT);
|
---|
| 364 | return;
|
---|
| 365 | }
|
---|
| 366 |
|
---|
| 367 | fibril_rwlock_read_lock(&vol->extents_lock);
|
---|
[ac4b70b] | 368 | fibril_rwlock_write_lock(&vol->states_lock);
|
---|
[d1d355f] | 369 |
|
---|
[56602e0] | 370 | switch (vol->extents[fail_extent].state) {
|
---|
[ac4b70b] | 371 | case HR_EXT_NONE:
|
---|
| 372 | case HR_EXT_MISSING:
|
---|
| 373 | case HR_EXT_FAILED:
|
---|
| 374 | fibril_rwlock_write_unlock(&vol->states_lock);
|
---|
| 375 | fibril_rwlock_read_unlock(&vol->extents_lock);
|
---|
| 376 | async_answer_0(icall, EINVAL);
|
---|
| 377 | return;
|
---|
| 378 | default:
|
---|
[56602e0] | 379 | hr_update_ext_state(vol, fail_extent, HR_EXT_FAILED);
|
---|
[ac4b70b] | 380 | hr_mark_vol_state_dirty(vol);
|
---|
| 381 | }
|
---|
[d1d355f] | 382 |
|
---|
| 383 | fibril_rwlock_write_unlock(&vol->states_lock);
|
---|
[ac4b70b] | 384 | fibril_rwlock_read_unlock(&vol->extents_lock);
|
---|
[d1d355f] | 385 |
|
---|
[56602e0] | 386 | vol->hr_ops.state_event(vol);
|
---|
[d1d355f] | 387 |
|
---|
| 388 | async_answer_0(icall, EOK);
|
---|
| 389 | }
|
---|
| 390 |
|
---|
[31eb568] | 391 | /** Add hotspare to volume (server).
|
---|
| 392 | *
|
---|
| 393 | * Adds hotspare to a volume.
|
---|
| 394 | */
|
---|
[5b320ac] | 395 | static void hr_add_hotspare_srv(ipc_call_t *icall)
|
---|
| 396 | {
|
---|
[a57dde4] | 397 | HR_DEBUG("%s()", __func__);
|
---|
[5b320ac] | 398 |
|
---|
| 399 | errno_t rc = EOK;
|
---|
| 400 | service_id_t vol_svc_id;
|
---|
| 401 | service_id_t hotspare;
|
---|
| 402 | hr_volume_t *vol;
|
---|
| 403 |
|
---|
| 404 | vol_svc_id = ipc_get_arg1(icall);
|
---|
| 405 | hotspare = ipc_get_arg2(icall);
|
---|
| 406 |
|
---|
| 407 | vol = hr_get_volume(vol_svc_id);
|
---|
| 408 | if (vol == NULL) {
|
---|
| 409 | async_answer_0(icall, ENOENT);
|
---|
| 410 | return;
|
---|
| 411 | }
|
---|
| 412 |
|
---|
| 413 | if (vol->hr_ops.add_hotspare == NULL) {
|
---|
[c6d2af8] | 414 | HR_NOTE("hotspare not supported on RAID level = %d, "
|
---|
| 415 | "metadata type = %s\n", vol->level,
|
---|
| 416 | hr_get_metadata_type_str(vol->meta_ops->get_type()));
|
---|
[5b320ac] | 417 | async_answer_0(icall, ENOTSUP);
|
---|
| 418 | return;
|
---|
| 419 | }
|
---|
| 420 |
|
---|
| 421 | rc = vol->hr_ops.add_hotspare(vol, hotspare);
|
---|
| 422 |
|
---|
| 423 | async_answer_0(icall, rc);
|
---|
| 424 | }
|
---|
| 425 |
|
---|
[31eb568] | 426 | /** Volume state printing (server).
|
---|
| 427 | *
|
---|
| 428 | * Prints info about all active volumes.
|
---|
| 429 | */
|
---|
[56602e0] | 430 | static void hr_print_state_srv(ipc_call_t *icall)
|
---|
[095a989] | 431 | {
|
---|
[a57dde4] | 432 | HR_DEBUG("%s()", __func__);
|
---|
[095a989] | 433 |
|
---|
| 434 | errno_t rc;
|
---|
| 435 | size_t vol_cnt = 0;
|
---|
| 436 | hr_vol_info_t info;
|
---|
| 437 | ipc_call_t call;
|
---|
| 438 | size_t size;
|
---|
| 439 |
|
---|
[8b51009] | 440 | fibril_rwlock_read_lock(&hr_volumes_lock);
|
---|
[095a989] | 441 |
|
---|
| 442 | vol_cnt = list_count(&hr_volumes);
|
---|
| 443 |
|
---|
| 444 | if (!async_data_read_receive(&call, &size)) {
|
---|
| 445 | rc = EREFUSED;
|
---|
| 446 | goto error;
|
---|
| 447 | }
|
---|
| 448 |
|
---|
| 449 | if (size != sizeof(size_t)) {
|
---|
| 450 | rc = EINVAL;
|
---|
| 451 | goto error;
|
---|
| 452 | }
|
---|
| 453 |
|
---|
| 454 | rc = async_data_read_finalize(&call, &vol_cnt, size);
|
---|
| 455 | if (rc != EOK)
|
---|
| 456 | goto error;
|
---|
| 457 |
|
---|
[b235c67] | 458 | list_foreach(hr_volumes, lvolumes, hr_volume_t, vol) {
|
---|
| 459 | memcpy(info.extents, vol->extents,
|
---|
[dfa2313] | 460 | sizeof(hr_extent_t) * HR_MAX_EXTENTS);
|
---|
[5b320ac] | 461 | memcpy(info.hotspares, vol->hotspares,
|
---|
| 462 | sizeof(hr_extent_t) * HR_MAX_HOTSPARES);
|
---|
[b235c67] | 463 | info.svc_id = vol->svc_id;
|
---|
[65706f1] | 464 | info.extent_no = vol->extent_no;
|
---|
[5b320ac] | 465 | info.hotspare_no = vol->hotspare_no;
|
---|
[b235c67] | 466 | info.level = vol->level;
|
---|
[b0f1366] | 467 | /* print usable number of blocks */
|
---|
[f647b87] | 468 | /* TODO: change to data_blkno */
|
---|
[b235c67] | 469 | info.nblocks = vol->data_blkno;
|
---|
| 470 | info.strip_size = vol->strip_size;
|
---|
| 471 | info.bsize = vol->bsize;
|
---|
[56602e0] | 472 | info.state = vol->state;
|
---|
[37a9c1e] | 473 | info.layout = vol->layout;
|
---|
[095a989] | 474 |
|
---|
| 475 | if (!async_data_read_receive(&call, &size)) {
|
---|
| 476 | rc = EREFUSED;
|
---|
| 477 | goto error;
|
---|
| 478 | }
|
---|
| 479 |
|
---|
| 480 | if (size != sizeof(hr_vol_info_t)) {
|
---|
| 481 | rc = EINVAL;
|
---|
| 482 | goto error;
|
---|
| 483 | }
|
---|
| 484 |
|
---|
| 485 | rc = async_data_read_finalize(&call, &info, size);
|
---|
| 486 | if (rc != EOK)
|
---|
| 487 | goto error;
|
---|
| 488 | }
|
---|
| 489 |
|
---|
[8b51009] | 490 | fibril_rwlock_read_unlock(&hr_volumes_lock);
|
---|
[095a989] | 491 | async_answer_0(icall, EOK);
|
---|
| 492 | return;
|
---|
| 493 | error:
|
---|
[8b51009] | 494 | fibril_rwlock_read_unlock(&hr_volumes_lock);
|
---|
[095a989] | 495 | async_answer_0(&call, rc);
|
---|
| 496 | async_answer_0(icall, rc);
|
---|
| 497 | }
|
---|
| 498 |
|
---|
[31eb568] | 499 | /** HelenRAID server control IPC methods crossroad.
|
---|
| 500 | */
|
---|
| 501 | static void hr_ctl_conn(ipc_call_t *icall)
|
---|
[94d84a0] | 502 | {
|
---|
[a57dde4] | 503 | HR_DEBUG("%s()", __func__);
|
---|
[94d84a0] | 504 |
|
---|
| 505 | async_accept_0(icall);
|
---|
| 506 |
|
---|
| 507 | while (true) {
|
---|
| 508 | ipc_call_t call;
|
---|
| 509 | async_get_call(&call);
|
---|
| 510 | sysarg_t method = ipc_get_imethod(&call);
|
---|
| 511 |
|
---|
| 512 | if (!method) {
|
---|
| 513 | async_answer_0(&call, EOK);
|
---|
| 514 | return;
|
---|
| 515 | }
|
---|
| 516 |
|
---|
| 517 | switch (method) {
|
---|
| 518 | case HR_CREATE:
|
---|
[d082801] | 519 | hr_create_srv(&call);
|
---|
[94d84a0] | 520 | break;
|
---|
[b0f1366] | 521 | case HR_ASSEMBLE:
|
---|
[d082801] | 522 | hr_assemble_srv(&call);
|
---|
[b0f1366] | 523 | break;
|
---|
[8b51009] | 524 | case HR_AUTO_ASSEMBLE:
|
---|
| 525 | hr_auto_assemble_srv(&call);
|
---|
| 526 | break;
|
---|
[a19d7fc4] | 527 | case HR_STOP:
|
---|
| 528 | hr_stop_srv(&call);
|
---|
| 529 | break;
|
---|
[d1d355f] | 530 | case HR_STOP_ALL:
|
---|
| 531 | hr_stop_all_srv(&call);
|
---|
| 532 | break;
|
---|
| 533 | case HR_FAIL_EXTENT:
|
---|
| 534 | hr_fail_extent_srv(&call);
|
---|
| 535 | break;
|
---|
[5b320ac] | 536 | case HR_ADD_HOTSPARE:
|
---|
| 537 | hr_add_hotspare_srv(&call);
|
---|
| 538 | break;
|
---|
[a19d7fc4] | 539 | case HR_STATUS:
|
---|
[56602e0] | 540 | hr_print_state_srv(&call);
|
---|
[a19d7fc4] | 541 | break;
|
---|
[94d84a0] | 542 | default:
|
---|
| 543 | async_answer_0(&call, EINVAL);
|
---|
| 544 | }
|
---|
| 545 | }
|
---|
| 546 | }
|
---|
| 547 |
|
---|
[31eb568] | 548 | /** HelenRAID server IPC method crossroad.
|
---|
| 549 | *
|
---|
| 550 | * Distinguishes between control IPC and block device
|
---|
| 551 | * IPC calls.
|
---|
| 552 | */
|
---|
[94d84a0] | 553 | static void hr_client_conn(ipc_call_t *icall, void *arg)
|
---|
| 554 | {
|
---|
[a57dde4] | 555 | HR_DEBUG("%s()", __func__);
|
---|
[94d84a0] | 556 |
|
---|
| 557 | hr_volume_t *vol;
|
---|
| 558 |
|
---|
[da5c257] | 559 | service_id_t svc_id = ipc_get_arg2(icall);
|
---|
[94d84a0] | 560 |
|
---|
| 561 | if (svc_id == ctl_sid) {
|
---|
[31eb568] | 562 | hr_ctl_conn(icall);
|
---|
[94d84a0] | 563 | } else {
|
---|
| 564 | vol = hr_get_volume(svc_id);
|
---|
| 565 | if (vol == NULL)
|
---|
[7bfe468] | 566 | async_answer_0(icall, ENOENT);
|
---|
[94d84a0] | 567 | bd_conn(icall, &vol->hr_bds);
|
---|
| 568 | }
|
---|
| 569 | }
|
---|
| 570 |
|
---|
| 571 | int main(int argc, char **argv)
|
---|
| 572 | {
|
---|
| 573 | errno_t rc;
|
---|
| 574 |
|
---|
| 575 | printf("%s: HelenRAID server\n", NAME);
|
---|
| 576 |
|
---|
| 577 | rc = log_init(NAME);
|
---|
| 578 | if (rc != EOK) {
|
---|
| 579 | printf("%s: failed to initialize logging\n", NAME);
|
---|
| 580 | return 1;
|
---|
| 581 | }
|
---|
| 582 |
|
---|
[8b51009] | 583 | fibril_rwlock_initialize(&hr_volumes_lock);
|
---|
[94d84a0] | 584 | list_initialize(&hr_volumes);
|
---|
| 585 |
|
---|
| 586 | async_set_fallback_port_handler(hr_client_conn, NULL);
|
---|
| 587 |
|
---|
| 588 | rc = loc_server_register(NAME, &hr_srv);
|
---|
| 589 | if (rc != EOK) {
|
---|
[d199a6f] | 590 | HR_ERROR("failed registering server: %s", str_error(rc));
|
---|
[94d84a0] | 591 | return EEXIST;
|
---|
| 592 | }
|
---|
| 593 |
|
---|
| 594 | rc = loc_service_register(hr_srv, SERVICE_NAME_HR, &ctl_sid);
|
---|
| 595 | if (rc != EOK) {
|
---|
[d199a6f] | 596 | HR_ERROR("failed registering service: %s", str_error(rc));
|
---|
[94d84a0] | 597 | return EEXIST;
|
---|
| 598 | }
|
---|
| 599 |
|
---|
[a056759] | 600 | printf("%s: Accepting connections.\n", NAME);
|
---|
[94d84a0] | 601 | task_retval(0);
|
---|
| 602 | async_manager();
|
---|
| 603 |
|
---|
| 604 | return 0;
|
---|
| 605 | }
|
---|
| 606 |
|
---|
| 607 | /** @}
|
---|
| 608 | */
|
---|