Changeset 13f4c85 in mainline
- Timestamp:
- 2025-06-23T10:54:34Z (4 months ago)
- Children:
- a5a2dcf
- Parents:
- 8b0fbb7
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/bd/hr/raid1.c
r8b0fbb7 r13f4c85 59 59 static size_t hr_raid1_count_good_extents(hr_volume_t *, uint64_t, size_t, 60 60 uint64_t); 61 static errno_t hr_raid1_bd_op(hr_bd_op_type_t, bd_srv_t *, aoff64_t, size_t,61 static errno_t hr_raid1_bd_op(hr_bd_op_type_t, hr_volume_t *, aoff64_t, size_t, 62 62 void *, const void *, size_t); 63 63 static errno_t hr_raid1_rebuild(void *); 64 64 static errno_t init_rebuild(hr_volume_t *, size_t *); 65 65 static errno_t swap_hs(hr_volume_t *, size_t, size_t); 66 static errno_t hr_raid1_restore_blocks(hr_volume_t *, size_t, uint64_t, size_t,67 void *);68 66 69 67 /* bdops */ … … 196 194 size_t healthy = hr_count_extents(vol, HR_EXT_ONLINE); 197 195 196 size_t invalid_no = hr_count_extents(vol, HR_EXT_INVALID); 197 198 fibril_mutex_lock(&vol->hotspare_lock); 199 size_t hs_no = vol->hotspare_no; 200 fibril_mutex_unlock(&vol->hotspare_lock); 201 198 202 fibril_rwlock_read_unlock(&vol->states_lock); 199 203 fibril_rwlock_read_unlock(&vol->extents_lock); … … 214 218 215 219 if (old_state != HR_VOL_REBUILD) { 216 /* XXX: allow REBUILD on INVALID extents */ 217 fibril_mutex_lock(&vol->hotspare_lock); 218 size_t hs_no = vol->hotspare_no; 219 fibril_mutex_unlock(&vol->hotspare_lock); 220 if (hs_no > 0) { 220 if (hs_no > 0 || invalid_no > 0) { 221 221 fid_t fib = fibril_create(hr_raid1_rebuild, 222 222 vol); … … 268 268 void *buf, size_t size) 269 269 { 270 return hr_raid1_bd_op(HR_BD_READ, bd, ba, cnt, buf, NULL, size); 270 hr_volume_t *vol = bd->srvs->sarg; 271 272 return hr_raid1_bd_op(HR_BD_READ, vol, ba, cnt, buf, NULL, size); 271 273 } 272 274 … … 274 276 const void *data, size_t size) 275 277 { 276 return hr_raid1_bd_op(HR_BD_WRITE, bd, ba, cnt, NULL, data, size); 278 hr_volume_t *vol = bd->srvs->sarg; 279 280 return hr_raid1_bd_op(HR_BD_WRITE, vol, ba, cnt, NULL, data, size); 277 281 } 278 282 … … 311 315 } 312 316 313 static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, bd_srv_t *bd, aoff64_t ba,314 size_t cnt, void *data_read, const void *data_write, size_t size)315 { 316 HR_DEBUG("%s()", __func__); 317 318 hr_volume_t *vol = bd->srvs->sarg; 317 static errno_t hr_raid1_bd_op(hr_bd_op_type_t type, hr_volume_t *vol, 318 aoff64_t ba, size_t cnt, void *data_read, const void *data_write, 319 size_t size) 320 { 321 HR_DEBUG("%s()", __func__); 322 319 323 hr_range_lock_t *rl = NULL; 320 324 errno_t rc; … … 452 456 void *buf = NULL; 453 457 size_t rebuild_idx; 458 hr_extent_t *rebuild_ext = NULL; 454 459 errno_t rc; 455 460 … … 458 463 return rc; 459 464 465 rebuild_ext = &vol->extents[rebuild_idx]; 466 460 467 size_t left = vol->data_blkno; 461 468 size_t max_blks = DATA_XFER_LIMIT / vol->bsize; 462 buf = malloc(max_blks * vol->bsize);469 buf = hr_malloc_waitok(max_blks * vol->bsize); 463 470 464 471 size_t cnt; … … 467 474 468 475 /* 469 * XXX: this is useless here after simplified DI, because 470 * rebuild cannot be triggered while ongoing rebuild 476 * this is not necessary because a rebuild is 477 * protected by itself, i.e. there can be only 478 * one REBUILD at a time 471 479 */ 472 480 fibril_rwlock_read_lock(&vol->extents_lock); … … 486 494 487 495 rl = hr_range_lock_acquire(vol, ba, cnt); 488 if (rl == NULL) {489 rc = ENOMEM;490 goto end;491 }492 496 493 497 atomic_store_explicit(&vol->rebuild_blk, ba, 494 498 memory_order_relaxed); 495 499 496 rc = hr_raid1_restore_blocks(vol, rebuild_idx, ba, cnt, buf); 500 rc = hr_raid1_bd_op(HR_BD_READ, vol, ba, cnt, buf, NULL, 501 cnt * vol->bsize); 502 if (rc != EOK) { 503 hr_range_lock_release(rl); 504 goto end; 505 } 506 507 rc = hr_write_direct(rebuild_ext->svc_id, ba, cnt, buf); 508 if (rc != EOK) { 509 hr_raid1_ext_state_cb(vol, rebuild_idx, rc); 510 hr_range_lock_release(rl); 511 goto end; 512 } 497 513 498 514 percent = ((ba + cnt) * 100) / vol->data_blkno; … … 505 521 hr_range_lock_release(rl); 506 522 507 if (rc != EOK)508 goto end;509 510 523 ba += cnt; 511 524 left -= cnt; … … 520 533 hr_update_ext_state(vol, rebuild_idx, HR_EXT_ONLINE); 521 534 522 /*523 * We can be optimistic here, if some extents are524 * still INVALID, FAULTY or MISSING, the update vol525 * function will pick them up, and set the volume526 * state accordingly.527 */528 hr_update_vol_state(vol, HR_VOL_OPTIMAL);529 535 hr_mark_vol_state_dirty(vol); 530 536 531 537 fibril_rwlock_write_unlock(&vol->states_lock); 532 538 533 (void)vol->meta_ops->save(vol, WITH_STATE_CALLBACK);539 /* (void)vol->meta_ops->save(vol, WITH_STATE_CALLBACK); */ 534 540 535 541 end: 536 if (rc != EOK) {537 /*538 * We can fail either because:539 * - the rebuild extent failing or invalidation540 * - there is are no ONLINE extents (vol is FAULTY)541 * - we got ENOMEM on all READs (we also invalidate the542 * rebuild extent here, for now)543 */544 fibril_rwlock_write_lock(&vol->states_lock);545 hr_update_vol_state(vol, HR_VOL_DEGRADED);546 hr_mark_vol_state_dirty(vol);547 fibril_rwlock_write_unlock(&vol->states_lock);548 }549 550 542 fibril_rwlock_read_unlock(&vol->extents_lock); 551 543 … … 565 557 fibril_rwlock_write_lock(&vol->states_lock); 566 558 fibril_mutex_lock(&vol->hotspare_lock); 567 568 /* XXX: allow REBUILD on INVALID extents */569 if (vol->hotspare_no == 0) {570 HR_WARN("hr_raid1_rebuild(): no free hotspares on \"%s\", "571 "aborting rebuild\n", vol->devname);572 rc = EINVAL;573 goto error;574 }575 559 576 560 size_t bad = vol->extent_no; … … 582 566 } 583 567 584 if (bad == vol->extent_no) { 585 HR_WARN("hr_raid1_rebuild(): no bad extent on \"%s\", " 586 "aborting rebuild\n", vol->devname); 568 if (bad == vol->extent_no) 587 569 rc = EINVAL; 570 else if (vol->state != HR_VOL_DEGRADED) 571 rc = EINVAL; 572 573 size_t invalid = vol->extent_no; 574 for (size_t i = 0; i < vol->extent_no; i++) { 575 if (vol->extents[i].state == HR_EXT_INVALID) { 576 invalid = i; 577 break; 578 } 579 } 580 581 if (invalid < vol->extent_no) 582 bad = invalid; 583 584 if (bad != invalid && vol->hotspare_no == 0) 585 rc = EINVAL; 586 587 if (rc != EOK) 588 588 goto error; 589 } 590 591 size_t hotspare_idx = vol->hotspare_no - 1; 592 593 hr_ext_state_t hs_state = vol->hotspares[hotspare_idx].state; 594 if (hs_state != HR_EXT_HOTSPARE) { 595 HR_ERROR("hr_raid1_rebuild(): invalid hotspare state \"%s\", " 596 "aborting rebuild\n", hr_get_ext_state_str(hs_state)); 597 rc = EINVAL; 598 goto error; 599 } 600 601 rc = swap_hs(vol, bad, hotspare_idx); 602 if (rc != EOK) { 603 HR_ERROR("hr_raid1_rebuild(): swapping hotspare failed, " 604 "aborting rebuild\n"); 605 goto error; 589 590 if (bad != invalid) { 591 size_t hotspare_idx = vol->hotspare_no - 1; 592 593 hr_ext_state_t hs_state = vol->hotspares[hotspare_idx].state; 594 if (hs_state != HR_EXT_HOTSPARE) { 595 HR_ERROR("hr_raid1_rebuild(): invalid hotspare" 596 "state \"%s\", aborting rebuild\n", 597 hr_get_ext_state_str(hs_state)); 598 rc = EINVAL; 599 goto error; 600 } 601 602 rc = swap_hs(vol, bad, hotspare_idx); 603 if (rc != EOK) { 604 HR_ERROR("hr_raid1_rebuild(): swapping " 605 "hotspare failed, aborting rebuild\n"); 606 goto error; 607 } 606 608 } 607 609 … … 627 629 static errno_t swap_hs(hr_volume_t *vol, size_t bad, size_t hs) 628 630 { 629 HR_DEBUG(" hr_raid1_rebuild(): swapping in hotspare\n");631 HR_DEBUG("%s()", __func__); 630 632 631 633 service_id_t faulty_svc_id = vol->extents[bad].svc_id; … … 646 648 } 647 649 648 static errno_t hr_raid1_restore_blocks(hr_volume_t *vol, size_t rebuild_idx,649 uint64_t ba, size_t cnt, void *buf)650 {651 assert(fibril_rwlock_is_locked(&vol->extents_lock));652 653 errno_t rc = ENOENT;654 hr_extent_t *ext, *rebuild_ext = &vol->extents[rebuild_idx];655 656 fibril_rwlock_read_lock(&vol->states_lock);657 hr_ext_state_t rebuild_ext_state = rebuild_ext->state;658 fibril_rwlock_read_unlock(&vol->states_lock);659 660 if (rebuild_ext_state != HR_EXT_REBUILD)661 return EINVAL;662 663 for (size_t i = 0; i < vol->extent_no; i++) {664 fibril_rwlock_read_lock(&vol->states_lock);665 ext = &vol->extents[i];666 if (ext->state != HR_EXT_ONLINE) {667 fibril_rwlock_read_unlock(&vol->states_lock);668 continue;669 }670 fibril_rwlock_read_unlock(&vol->states_lock);671 672 rc = block_read_direct(ext->svc_id, ba, cnt, buf);673 if (rc == EOK)674 break;675 676 if (rc != ENOMEM)677 hr_raid1_ext_state_cb(vol, i, rc);678 679 if (i + 1 >= vol->extent_no) {680 if (rc != ENOMEM) {681 HR_ERROR("rebuild on \"%s\" (%" PRIun "), "682 "failed due to too many failed extents\n",683 vol->devname, vol->svc_id);684 }685 686 /* for now we have to invalidate the rebuild extent */687 if (rc == ENOMEM) {688 HR_ERROR("rebuild on \"%s\" (%" PRIun "), "689 "failed due to too many failed reads, "690 "because of not enough memory\n",691 vol->devname, vol->svc_id);692 hr_raid1_ext_state_cb(vol, rebuild_idx,693 ENOMEM);694 }695 696 return rc;697 }698 }699 700 rc = block_write_direct(rebuild_ext->svc_id, ba, cnt, buf);701 if (rc != EOK) {702 /*703 * Here we dont handle ENOMEM, because maybe in the704 * future, there is going to be M_WAITOK, or we are705 * going to wait for more memory, so that we don't706 * have to invalidate it...707 *708 * XXX: for now we do709 */710 hr_raid1_ext_state_cb(vol, rebuild_idx, rc);711 712 HR_ERROR("rebuild on \"%s\" (%" PRIun "), failed due to "713 "the rebuilt extent no. %zu WRITE (rc: %s)\n",714 vol->devname, vol->svc_id, rebuild_idx, str_error(rc));715 716 return rc;717 }718 719 return EOK;720 }721 722 650 /** @} 723 651 */
Note:
See TracChangeset
for help on using the changeset viewer.