Changeset 13f4c85 in mainline


Ignore:
Timestamp:
2025-06-23T10:54:34Z (4 months ago)
Author:
Miroslav Cimerman <mc@…>
Children:
a5a2dcf
Parents:
8b0fbb7
Message:

hr: raid1.c: allow rebuild on INVALID extents

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/bd/hr/raid1.c

    r8b0fbb7 r13f4c85  
    5959static size_t hr_raid1_count_good_extents(hr_volume_t *, uint64_t, size_t,
    6060    uint64_t);
    61 static errno_t hr_raid1_bd_op(hr_bd_op_type_t, bd_srv_t *, aoff64_t, size_t,
     61static errno_t hr_raid1_bd_op(hr_bd_op_type_t, hr_volume_t *, aoff64_t, size_t,
    6262    void *, const void *, size_t);
    6363static errno_t hr_raid1_rebuild(void *);
    6464static errno_t init_rebuild(hr_volume_t *, size_t *);
    6565static 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 *);
    6866
    6967/* bdops */
     
    196194        size_t healthy = hr_count_extents(vol, HR_EXT_ONLINE);
    197195
     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
    198202        fibril_rwlock_read_unlock(&vol->states_lock);
    199203        fibril_rwlock_read_unlock(&vol->extents_lock);
     
    214218
    215219                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) {
    221221                                fid_t fib = fibril_create(hr_raid1_rebuild,
    222222                                    vol);
     
    268268    void *buf, size_t size)
    269269{
    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);
    271273}
    272274
     
    274276    const void *data, size_t size)
    275277{
    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);
    277281}
    278282
     
    311315}
    312316
    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;
     317static 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
    319323        hr_range_lock_t *rl = NULL;
    320324        errno_t rc;
     
    452456        void *buf = NULL;
    453457        size_t rebuild_idx;
     458        hr_extent_t *rebuild_ext = NULL;
    454459        errno_t rc;
    455460
     
    458463                return rc;
    459464
     465        rebuild_ext = &vol->extents[rebuild_idx];
     466
    460467        size_t left = vol->data_blkno;
    461468        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);
    463470
    464471        size_t cnt;
     
    467474
    468475        /*
    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
    471479         */
    472480        fibril_rwlock_read_lock(&vol->extents_lock);
     
    486494
    487495                rl = hr_range_lock_acquire(vol, ba, cnt);
    488                 if (rl == NULL) {
    489                         rc = ENOMEM;
    490                         goto end;
    491                 }
    492496
    493497                atomic_store_explicit(&vol->rebuild_blk, ba,
    494498                    memory_order_relaxed);
    495499
    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                }
    497513
    498514                percent = ((ba + cnt) * 100) / vol->data_blkno;
     
    505521                hr_range_lock_release(rl);
    506522
    507                 if (rc != EOK)
    508                         goto end;
    509 
    510523                ba += cnt;
    511524                left -= cnt;
     
    520533        hr_update_ext_state(vol, rebuild_idx, HR_EXT_ONLINE);
    521534
    522         /*
    523          * We can be optimistic here, if some extents are
    524          * still INVALID, FAULTY or MISSING, the update vol
    525          * function will pick them up, and set the volume
    526          * state accordingly.
    527          */
    528         hr_update_vol_state(vol, HR_VOL_OPTIMAL);
    529535        hr_mark_vol_state_dirty(vol);
    530536
    531537        fibril_rwlock_write_unlock(&vol->states_lock);
    532538
    533         (void)vol->meta_ops->save(vol, WITH_STATE_CALLBACK);
     539        /* (void)vol->meta_ops->save(vol, WITH_STATE_CALLBACK); */
    534540
    535541end:
    536         if (rc != EOK) {
    537                 /*
    538                  * We can fail either because:
    539                  * - the rebuild extent failing or invalidation
    540                  * - there is are no ONLINE extents (vol is FAULTY)
    541                  * - we got ENOMEM on all READs (we also invalidate the
    542                  *   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 
    550542        fibril_rwlock_read_unlock(&vol->extents_lock);
    551543
     
    565557        fibril_rwlock_write_lock(&vol->states_lock);
    566558        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         }
    575559
    576560        size_t bad = vol->extent_no;
     
    582566        }
    583567
    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)
    587569                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)
    588588                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                }
    606608        }
    607609
     
    627629static errno_t swap_hs(hr_volume_t *vol, size_t bad, size_t hs)
    628630{
    629         HR_DEBUG("hr_raid1_rebuild(): swapping in hotspare\n");
     631        HR_DEBUG("%s()", __func__);
    630632
    631633        service_id_t faulty_svc_id = vol->extents[bad].svc_id;
     
    646648}
    647649
    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 the
    704                  * future, there is going to be M_WAITOK, or we are
    705                  * going to wait for more memory, so that we don't
    706                  * have to invalidate it...
    707                  *
    708                  * XXX: for now we do
    709                  */
    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 
    722650/** @}
    723651 */
Note: See TracChangeset for help on using the changeset viewer.