source: mainline/uspace/srv/bd/hr/raid1.c@ a5ec426

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

hr: extent init refactor, blkno truncation

  • Property mode set to 100644
File size: 18.2 KB
Line 
1/*
2 * Copyright (c) 2025 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 <bd_srv.h>
37#include <block.h>
38#include <errno.h>
39#include <hr.h>
40#include <io/log.h>
41#include <ipc/hr.h>
42#include <ipc/services.h>
43#include <loc.h>
44#include <task.h>
45#include <stdatomic.h>
46#include <stdio.h>
47#include <stdlib.h>
48#include <str_error.h>
49
50#include "fge.h"
51#include "io.h"
52#include "superblock.h"
53#include "util.h"
54#include "var.h"
55
56static void hr_raid1_update_vol_status(hr_volume_t *);
57static void hr_raid1_ext_state_callback(hr_volume_t *, size_t, errno_t);
58static size_t hr_raid1_count_good_extents(hr_volume_t *, uint64_t, size_t,
59 uint64_t);
60static errno_t hr_raid1_bd_op(hr_bd_op_type_t, bd_srv_t *, aoff64_t, size_t,
61 void *, const void *, size_t);
62static errno_t hr_raid1_rebuild(void *);
63static errno_t init_rebuild(hr_volume_t *, size_t *);
64static errno_t swap_hs(hr_volume_t *, size_t, size_t);
65static errno_t hr_raid1_restore_blocks(hr_volume_t *, size_t, uint64_t, size_t,
66 void *);
67
68/* bdops */
69static errno_t hr_raid1_bd_open(bd_srvs_t *, bd_srv_t *);
70static errno_t hr_raid1_bd_close(bd_srv_t *);
71static errno_t hr_raid1_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *,
72 size_t);
73static errno_t hr_raid1_bd_sync_cache(bd_srv_t *, aoff64_t, size_t);
74static errno_t hr_raid1_bd_write_blocks(bd_srv_t *, aoff64_t, size_t,
75 const void *, size_t);
76static errno_t hr_raid1_bd_get_block_size(bd_srv_t *, size_t *);
77static errno_t hr_raid1_bd_get_num_blocks(bd_srv_t *, aoff64_t *);
78
79static bd_ops_t hr_raid1_bd_ops = {
80 .open = hr_raid1_bd_open,
81 .close = hr_raid1_bd_close,
82 .sync_cache = hr_raid1_bd_sync_cache,
83 .read_blocks = hr_raid1_bd_read_blocks,
84 .write_blocks = hr_raid1_bd_write_blocks,
85 .get_block_size = hr_raid1_bd_get_block_size,
86 .get_num_blocks = hr_raid1_bd_get_num_blocks
87};
88
89extern loc_srv_t *hr_srv;
90
91errno_t hr_raid1_create(hr_volume_t *new_volume)
92{
93 HR_DEBUG("%s()", __func__);
94
95 assert(new_volume->level == HR_LVL_1);
96
97 if (new_volume->extent_no < 2) {
98 HR_ERROR("RAID 1 array needs at least 2 devices\n");
99 return EINVAL;
100 }
101
102 bd_srvs_init(&new_volume->hr_bds);
103 new_volume->hr_bds.ops = &hr_raid1_bd_ops;
104 new_volume->hr_bds.sarg = new_volume;
105
106 /* force volume state update */
107 hr_mark_vol_state_dirty(new_volume);
108 hr_raid1_update_vol_status(new_volume);
109
110 fibril_rwlock_read_lock(&new_volume->states_lock);
111 hr_vol_status_t state = new_volume->status;
112 fibril_rwlock_read_unlock(&new_volume->states_lock);
113 if (state == HR_VOL_FAULTY || state == HR_VOL_NONE)
114 return EINVAL;
115
116 return EOK;
117}
118
119/*
120 * Called only once in volume's lifetime.
121 */
122errno_t hr_raid1_init(hr_volume_t *vol)
123{
124 HR_DEBUG("%s()", __func__);
125
126 assert(vol->level == HR_LVL_1);
127
128 uint64_t truncated_blkno = vol->extents[0].blkno;
129 for (size_t i = 1; i < vol->extent_no; i++) {
130 if (vol->extents[i].blkno < truncated_blkno)
131 truncated_blkno = vol->extents[i].blkno;
132 }
133
134 vol->truncated_blkno = truncated_blkno;
135 vol->nblocks = truncated_blkno;
136 vol->data_offset = HR_DATA_OFF;
137 vol->data_blkno = truncated_blkno - HR_META_SIZE;
138 vol->strip_size = 0;
139
140 return EOK;
141}
142
143void hr_raid1_status_event(hr_volume_t *vol)
144{
145 HR_DEBUG("%s()", __func__);
146
147 hr_raid1_update_vol_status(vol);
148}
149
150errno_t hr_raid1_add_hotspare(hr_volume_t *vol, service_id_t hotspare)
151{
152 HR_DEBUG("%s()", __func__);
153
154 errno_t rc = hr_util_add_hotspare(vol, hotspare);
155
156 hr_raid1_update_vol_status(vol);
157
158 return rc;
159}
160
161static errno_t hr_raid1_bd_open(bd_srvs_t *bds, bd_srv_t *bd)
162{
163 HR_DEBUG("%s()", __func__);
164
165 hr_volume_t *vol = bd->srvs->sarg;
166
167 atomic_fetch_add_explicit(&vol->open_cnt, 1, memory_order_relaxed);
168
169 return EOK;
170}
171
172static errno_t hr_raid1_bd_close(bd_srv_t *bd)
173{
174 HR_DEBUG("%s()", __func__);
175
176 hr_volume_t *vol = bd->srvs->sarg;
177
178 atomic_fetch_sub_explicit(&vol->open_cnt, 1, memory_order_relaxed);
179
180 return EOK;
181}
182
183static errno_t hr_raid1_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt)
184{
185 return hr_raid1_bd_op(HR_BD_SYNC, bd, ba, cnt, NULL, NULL, 0);
186}
187
188static errno_t hr_raid1_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt,
189 void *buf, size_t size)
190{
191 return hr_raid1_bd_op(HR_BD_READ, bd, ba, cnt, buf, NULL, size);
192}
193
194static errno_t hr_raid1_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt,
195 const void *data, size_t size)
196{
197 return hr_raid1_bd_op(HR_BD_WRITE, bd, ba, cnt, NULL, data, size);
198}
199
200static errno_t hr_raid1_bd_get_block_size(bd_srv_t *bd, size_t *rsize)
201{
202 hr_volume_t *vol = bd->srvs->sarg;
203
204 *rsize = vol->bsize;
205 return EOK;
206}
207
208static errno_t hr_raid1_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb)
209{
210 hr_volume_t *vol = bd->srvs->sarg;
211
212 *rnb = vol->data_blkno;
213 return EOK;
214}
215
216static void hr_raid1_update_vol_status(hr_volume_t *vol)
217{
218 bool exp = true;
219
220 /* TODO: could also wrap this */
221 if (!atomic_compare_exchange_strong(&vol->state_dirty, &exp, false))
222 return;
223
224 fibril_rwlock_read_lock(&vol->extents_lock);
225 fibril_rwlock_read_lock(&vol->states_lock);
226
227 hr_vol_status_t old_state = vol->status;
228 size_t healthy = hr_count_extents(vol, HR_EXT_ONLINE);
229
230 fibril_rwlock_read_unlock(&vol->states_lock);
231 fibril_rwlock_read_unlock(&vol->extents_lock);
232
233 if (healthy == 0) {
234 if (old_state != HR_VOL_FAULTY) {
235 fibril_rwlock_write_lock(&vol->states_lock);
236 hr_update_vol_status(vol, HR_VOL_FAULTY);
237 fibril_rwlock_write_unlock(&vol->states_lock);
238 }
239 } else if (healthy < vol->extent_no) {
240 if (old_state != HR_VOL_REBUILD &&
241 old_state != HR_VOL_DEGRADED) {
242 fibril_rwlock_write_lock(&vol->states_lock);
243 hr_update_vol_status(vol, HR_VOL_DEGRADED);
244 fibril_rwlock_write_unlock(&vol->states_lock);
245 }
246
247 if (old_state != HR_VOL_REBUILD) {
248 if (vol->hotspare_no > 0) {
249 fid_t fib = fibril_create(hr_raid1_rebuild,
250 vol);
251 if (fib == 0)
252 return;
253 fibril_start(fib);
254 fibril_detach(fib);
255 }
256 }
257 } else {
258 if (old_state != HR_VOL_ONLINE) {
259 fibril_rwlock_write_lock(&vol->states_lock);
260 hr_update_vol_status(vol, HR_VOL_ONLINE);
261 fibril_rwlock_write_unlock(&vol->states_lock);
262 }
263 }
264}
265
266static void hr_raid1_ext_state_callback(hr_volume_t *vol, size_t extent,
267 errno_t rc)
268{
269 if (rc == EOK)
270 return;
271
272 assert(fibril_rwlock_is_locked(&vol->extents_lock));
273
274 fibril_rwlock_write_lock(&vol->states_lock);
275
276 switch (rc) {
277 case ENOMEM:
278 hr_update_ext_status(vol, extent, HR_EXT_INVALID);
279 break;
280 case ENOENT:
281 hr_update_ext_status(vol, extent, HR_EXT_MISSING);
282 break;
283 default:
284 hr_update_ext_status(vol, extent, HR_EXT_FAILED);
285 }
286
287 hr_mark_vol_state_dirty(vol);
288
289 fibril_rwlock_write_unlock(&vol->states_lock);
290}
291
292static size_t hr_raid1_count_good_extents(hr_volume_t *vol, uint64_t ba,
293 size_t cnt, uint64_t rebuild_blk)
294{
295 assert(fibril_rwlock_is_locked(&vol->extents_lock));
296 assert(fibril_rwlock_is_locked(&vol->states_lock));
297
298 size_t count = 0;
299 for (size_t i = 0; i < vol->extent_no; i++) {
300 if (vol->extents[i].status == HR_EXT_ONLINE ||
301 (vol->extents[i].status == HR_EXT_REBUILD &&
302 ba < rebuild_blk)) {
303 count++;
304 }
305 }
306
307 return count;
308
309}
310
311static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba,
312 size_t cnt, void *data_read, const void *data_write, size_t size)
313{
314 hr_volume_t *vol = bd->srvs->sarg;
315 hr_range_lock_t *rl = NULL;
316 errno_t rc;
317 size_t i;
318 uint64_t rebuild_blk;
319
320 fibril_rwlock_read_lock(&vol->states_lock);
321 hr_vol_status_t vol_state = vol->status;
322 fibril_rwlock_read_unlock(&vol->states_lock);
323
324 if (vol_state == HR_VOL_FAULTY || vol_state == HR_VOL_NONE)
325 return EIO;
326
327 if (type == HR_BD_READ || type == HR_BD_WRITE)
328 if (size < cnt * vol->bsize)
329 return EINVAL;
330
331 rc = hr_check_ba_range(vol, cnt, ba);
332 if (rc != EOK)
333 return rc;
334
335 /* allow full dev sync */
336 if (type != HR_BD_SYNC || ba != 0)
337 hr_add_ba_offset(vol, &ba);
338
339 /*
340 * extent order has to be locked for the whole IO duration,
341 * so that workers have consistent targets
342 */
343 fibril_rwlock_read_lock(&vol->extents_lock);
344
345 size_t successful = 0;
346 switch (type) {
347 case HR_BD_READ:
348 rebuild_blk = atomic_load_explicit(&vol->rebuild_blk,
349 memory_order_relaxed);
350
351 for (i = 0; i < vol->extent_no; i++) {
352 fibril_rwlock_read_lock(&vol->states_lock);
353 hr_ext_status_t state = vol->extents[i].status;
354 fibril_rwlock_read_unlock(&vol->states_lock);
355
356 if (state != HR_EXT_ONLINE &&
357 (state != HR_EXT_REBUILD ||
358 ba + cnt - 1 >= rebuild_blk)) {
359 continue;
360 }
361
362 rc = block_read_direct(vol->extents[i].svc_id, ba, cnt,
363 data_read);
364
365 if (rc == ENOMEM && i + 1 == vol->extent_no)
366 goto end;
367
368 if (rc == ENOMEM)
369 continue;
370
371 if (rc != EOK) {
372 hr_raid1_ext_state_callback(vol, i, rc);
373 } else {
374 successful++;
375 break;
376 }
377 }
378 break;
379 case HR_BD_SYNC:
380 case HR_BD_WRITE:
381 if (type == HR_BD_WRITE) {
382 rl = hr_range_lock_acquire(vol, ba, cnt);
383 if (rl == NULL) {
384 rc = ENOMEM;
385 goto end;
386 }
387 }
388
389 fibril_rwlock_read_lock(&vol->states_lock);
390
391 rebuild_blk = atomic_load_explicit(&vol->rebuild_blk,
392 memory_order_relaxed);
393
394 size_t good = hr_raid1_count_good_extents(vol, ba, cnt,
395 rebuild_blk);
396
397 hr_fgroup_t *group = hr_fgroup_create(vol->fge, good);
398 if (group == NULL) {
399 if (type == HR_BD_WRITE)
400 hr_range_lock_release(rl);
401 rc = ENOMEM;
402 fibril_rwlock_read_unlock(&vol->states_lock);
403 goto end;
404 }
405
406 for (i = 0; i < vol->extent_no; i++) {
407 if (vol->extents[i].status != HR_EXT_ONLINE &&
408 (vol->extents[i].status != HR_EXT_REBUILD ||
409 ba >= rebuild_blk)) {
410 /*
411 * When the extent is being rebuilt,
412 * we only write to the part that is already
413 * rebuilt. If IO starts after vol->rebuild_blk
414 * we do not proceed, the write is going to
415 * be replicated later in the rebuild.
416 */
417 continue;
418 }
419
420 hr_io_t *io = hr_fgroup_alloc(group);
421 io->extent = i;
422 io->data_write = data_write;
423 io->data_read = data_read;
424 io->ba = ba;
425 io->cnt = cnt;
426 io->type = type;
427 io->vol = vol;
428 io->state_callback = hr_raid1_ext_state_callback;
429
430 hr_fgroup_submit(group, hr_io_worker, io);
431 }
432
433 fibril_rwlock_read_unlock(&vol->states_lock);
434
435 (void)hr_fgroup_wait(group, &successful, NULL);
436
437 if (type == HR_BD_WRITE)
438 hr_range_lock_release(rl);
439
440 break;
441 default:
442 rc = EINVAL;
443 goto end;
444 }
445
446 if (successful > 0)
447 rc = EOK;
448 else
449 rc = EIO;
450
451end:
452 fibril_rwlock_read_unlock(&vol->extents_lock);
453
454 hr_raid1_update_vol_status(vol);
455
456 return rc;
457}
458
459/*
460 * Put the last HOTSPARE extent in place
461 * of first that != ONLINE, and start the rebuild.
462 */
463static errno_t hr_raid1_rebuild(void *arg)
464{
465 HR_DEBUG("%s()", __func__);
466
467 hr_volume_t *vol = arg;
468 void *buf = NULL;
469 size_t rebuild_idx;
470 errno_t rc;
471
472 rc = init_rebuild(vol, &rebuild_idx);
473 if (rc != EOK)
474 return rc;
475
476 size_t left = vol->data_blkno;
477 size_t max_blks = DATA_XFER_LIMIT / vol->bsize;
478 buf = malloc(max_blks * vol->bsize);
479
480 size_t cnt;
481 uint64_t ba = 0;
482 hr_add_ba_offset(vol, &ba);
483
484 /*
485 * XXX: this is useless here after simplified DI, because
486 * rebuild cannot be triggered while ongoing rebuild
487 */
488 fibril_rwlock_read_lock(&vol->extents_lock);
489
490 hr_range_lock_t *rl = NULL;
491
492 unsigned int percent, old_percent = 100;
493 while (left != 0) {
494 cnt = min(max_blks, left);
495
496 rl = hr_range_lock_acquire(vol, ba, cnt);
497 if (rl == NULL) {
498 rc = ENOMEM;
499 goto end;
500 }
501
502 atomic_store_explicit(&vol->rebuild_blk, ba,
503 memory_order_relaxed);
504
505 rc = hr_raid1_restore_blocks(vol, rebuild_idx, ba, cnt, buf);
506
507 percent = ((ba + cnt) * 100) / vol->data_blkno;
508 if (percent != old_percent) {
509 if (percent % 5 == 0)
510 HR_DEBUG("\"%s\" REBUILD progress: %u%%\n",
511 vol->devname, percent);
512 }
513
514 hr_range_lock_release(rl);
515
516 if (rc != EOK)
517 goto end;
518
519 ba += cnt;
520 left -= cnt;
521 old_percent = percent;
522 }
523
524 HR_DEBUG("hr_raid1_rebuild(): rebuild finished on \"%s\" (%lu), "
525 "extent no. %lu\n", vol->devname, vol->svc_id, rebuild_idx);
526
527 fibril_rwlock_write_lock(&vol->states_lock);
528
529 hr_update_ext_status(vol, rebuild_idx, HR_EXT_ONLINE);
530
531 /*
532 * We can be optimistic here, if some extents are
533 * still INVALID, FAULTY or MISSING, the update vol
534 * function will pick them up, and set the volume
535 * state accordingly.
536 */
537 hr_update_vol_status(vol, HR_VOL_ONLINE);
538 hr_mark_vol_state_dirty(vol);
539
540 fibril_rwlock_write_unlock(&vol->states_lock);
541
542 /*
543 * For now write metadata at the end, because
544 * we don't sync metada accross extents yet.
545 */
546 hr_write_meta_to_ext(vol, rebuild_idx);
547end:
548 if (rc != EOK) {
549 /*
550 * We can fail either because:
551 * - the rebuild extent failing or invalidation
552 * - there is are no ONLINE extents (vol is FAULTY)
553 * - we got ENOMEM on all READs (we also invalidate the
554 * rebuild extent here, for now)
555 */
556 fibril_rwlock_write_lock(&vol->states_lock);
557 hr_update_vol_status(vol, HR_VOL_DEGRADED);
558 hr_mark_vol_state_dirty(vol);
559 fibril_rwlock_write_unlock(&vol->states_lock);
560 }
561
562 fibril_rwlock_read_unlock(&vol->extents_lock);
563
564 hr_raid1_update_vol_status(vol);
565
566 if (buf != NULL)
567 free(buf);
568
569 return rc;
570}
571
572static errno_t init_rebuild(hr_volume_t *vol, size_t *rebuild_idx)
573{
574 errno_t rc = EOK;
575
576 fibril_rwlock_write_lock(&vol->extents_lock);
577 fibril_rwlock_write_lock(&vol->states_lock);
578 fibril_mutex_lock(&vol->hotspare_lock);
579
580 if (vol->hotspare_no == 0) {
581 HR_WARN("hr_raid1_rebuild(): no free hotspares on \"%s\", "
582 "aborting rebuild\n", vol->devname);
583 rc = EINVAL;
584 goto error;
585 }
586
587 size_t bad = vol->extent_no;
588 for (size_t i = 0; i < vol->extent_no; i++) {
589 if (vol->extents[i].status != HR_EXT_ONLINE) {
590 bad = i;
591 break;
592 }
593 }
594
595 if (bad == vol->extent_no) {
596 HR_WARN("hr_raid1_rebuild(): no bad extent on \"%s\", "
597 "aborting rebuild\n", vol->devname);
598 rc = EINVAL;
599 goto error;
600 }
601
602 size_t hotspare_idx = vol->hotspare_no - 1;
603
604 hr_ext_status_t hs_state = vol->hotspares[hotspare_idx].status;
605 if (hs_state != HR_EXT_HOTSPARE) {
606 HR_ERROR("hr_raid1_rebuild(): invalid hotspare state \"%s\", "
607 "aborting rebuild\n", hr_get_ext_status_msg(hs_state));
608 rc = EINVAL;
609 goto error;
610 }
611
612 rc = swap_hs(vol, bad, hotspare_idx);
613 if (rc != EOK) {
614 HR_ERROR("hr_raid1_rebuild(): swapping hotspare failed, "
615 "aborting rebuild\n");
616 goto error;
617 }
618
619 hr_extent_t *rebuild_ext = &vol->extents[bad];
620
621 HR_DEBUG("hr_raid1_rebuild(): starting REBUILD on extent no. %lu (%lu)"
622 "\n", bad, rebuild_ext->svc_id);
623
624 atomic_store_explicit(&vol->rebuild_blk, 0, memory_order_relaxed);
625
626 hr_update_ext_status(vol, bad, HR_EXT_REBUILD);
627 hr_update_vol_status(vol, HR_VOL_REBUILD);
628
629 *rebuild_idx = bad;
630error:
631 fibril_mutex_unlock(&vol->hotspare_lock);
632 fibril_rwlock_write_unlock(&vol->states_lock);
633 fibril_rwlock_write_unlock(&vol->extents_lock);
634
635 return rc;
636}
637
638static errno_t swap_hs(hr_volume_t *vol, size_t bad, size_t hs)
639{
640 HR_DEBUG("hr_raid1_rebuild(): swapping in hotspare\n");
641
642 service_id_t faulty_svc_id = vol->extents[bad].svc_id;
643 service_id_t hs_svc_id = vol->hotspares[hs].svc_id;
644
645 hr_update_ext_svc_id(vol, bad, hs_svc_id);
646 hr_update_ext_status(vol, bad, HR_EXT_HOTSPARE);
647
648 hr_update_hotspare_svc_id(vol, hs, 0);
649 hr_update_hotspare_status(vol, hs, HR_EXT_MISSING);
650
651 vol->hotspare_no--;
652
653 if (faulty_svc_id != 0)
654 block_fini(faulty_svc_id);
655
656 return EOK;
657}
658
659static errno_t hr_raid1_restore_blocks(hr_volume_t *vol, size_t rebuild_idx,
660 uint64_t ba, size_t cnt, void *buf)
661{
662 assert(fibril_rwlock_is_locked(&vol->extents_lock));
663
664 errno_t rc = ENOENT;
665 hr_extent_t *ext, *rebuild_ext = &vol->extents[rebuild_idx];
666
667 fibril_rwlock_read_lock(&vol->states_lock);
668 hr_ext_status_t rebuild_ext_status = rebuild_ext->status;
669 fibril_rwlock_read_unlock(&vol->states_lock);
670
671 if (rebuild_ext_status != HR_EXT_REBUILD)
672 return EINVAL;
673
674 for (size_t i = 0; i < vol->extent_no; i++) {
675 fibril_rwlock_read_lock(&vol->states_lock);
676 ext = &vol->extents[i];
677 if (ext->status != HR_EXT_ONLINE) {
678 fibril_rwlock_read_unlock(&vol->states_lock);
679 continue;
680 }
681 fibril_rwlock_read_unlock(&vol->states_lock);
682
683 rc = block_read_direct(ext->svc_id, ba, cnt, buf);
684 if (rc == EOK)
685 break;
686
687 if (rc != ENOMEM)
688 hr_raid1_ext_state_callback(vol, i, rc);
689
690 if (i + 1 >= vol->extent_no) {
691 if (rc != ENOMEM) {
692 HR_ERROR("rebuild on \"%s\" (%lu), failed due "
693 "to too many failed extents\n",
694 vol->devname, vol->svc_id);
695 }
696
697 /* for now we have to invalidate the rebuild extent */
698 if (rc == ENOMEM) {
699 HR_ERROR("rebuild on \"%s\" (%lu), failed due "
700 "to too many failed reads, because of not "
701 "enough memory\n",
702 vol->devname, vol->svc_id);
703 hr_raid1_ext_state_callback(vol, rebuild_idx,
704 ENOMEM);
705 }
706
707 return rc;
708 }
709 }
710
711 rc = block_write_direct(rebuild_ext->svc_id, ba, cnt, buf);
712 if (rc != EOK) {
713 /*
714 * Here we dont handle ENOMEM, because maybe in the
715 * future, there is going to be M_WAITOK, or we are
716 * going to wait for more memory, so that we don't
717 * have to invalidate it...
718 *
719 * XXX: for now we do
720 */
721 hr_raid1_ext_state_callback(vol, rebuild_idx, rc);
722
723 HR_ERROR("rebuild on \"%s\" (%lu), failed due to "
724 "the rebuilt extent no. %lu WRITE (rc: %s)\n",
725 vol->devname, vol->svc_id, rebuild_idx, str_error(rc));
726
727 return rc;
728 }
729
730 return EOK;
731}
732
733/** @}
734 */
Note: See TracBrowser for help on using the repository browser.