Changeset 5b320ac in mainline for uspace/srv


Ignore:
Timestamp:
2024-11-22T18:38:49Z (11 months ago)
Author:
Miroslav Cimerman <mc@…>
Children:
d0f0744
Parents:
06f2762
Message:

hr: hotspares + RAID1 rebuild

Location:
uspace/srv/bd/hr
Files:
3 edited

Legend:

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

    r06f2762 r5b320ac  
    191191                new_volume->hr_ops.init = hr_raid1_init;
    192192                new_volume->hr_ops.status_event = hr_raid1_status_event;
     193                new_volume->hr_ops.add_hotspare = hr_raid1_add_hotspare;
    193194                break;
    194195        case HR_LVL_0:
     
    287288}
    288289
     290static void hr_add_hotspare_srv(ipc_call_t *icall)
     291{
     292        HR_DEBUG("hr_add_hotspare()\n");
     293
     294        errno_t rc = EOK;
     295        service_id_t vol_svc_id;
     296        service_id_t hotspare;
     297        hr_volume_t *vol;
     298
     299        vol_svc_id = ipc_get_arg1(icall);
     300        hotspare = ipc_get_arg2(icall);
     301
     302        vol = hr_get_volume(vol_svc_id);
     303        if (vol == NULL) {
     304                async_answer_0(icall, ENOENT);
     305                return;
     306        }
     307
     308        if (vol->hr_ops.add_hotspare == NULL) {
     309                HR_DEBUG("hr_add_hotspare(): not supported on RAID level %d\n",
     310                    vol->level);
     311                async_answer_0(icall, ENOTSUP);
     312                return;
     313        }
     314
     315        rc = vol->hr_ops.add_hotspare(vol, hotspare);
     316
     317        async_answer_0(icall, rc);
     318}
     319
    289320static void hr_print_status_srv(ipc_call_t *icall)
    290321{
     
    318349                memcpy(info.extents, vol->extents,
    319350                    sizeof(hr_extent_t) * HR_MAX_EXTENTS);
     351                memcpy(info.hotspares, vol->hotspares,
     352                    sizeof(hr_extent_t) * HR_MAX_HOTSPARES);
    320353                info.svc_id = vol->svc_id;
    321354                info.extent_no = vol->dev_no;
     355                info.hotspare_no = vol->hotspare_no;
    322356                info.level = vol->level;
    323357                /* print usable number of blocks */
     
    377411                        hr_stop_srv(&call);
    378412                        break;
     413                case HR_ADD_HOTSPARE:
     414                        hr_add_hotspare_srv(&call);
     415                        break;
    379416                case HR_STATUS:
    380417                        hr_print_status_srv(&call);
  • uspace/srv/bd/hr/raid1.c

    r06f2762 r5b320ac  
    5858static errno_t hr_raid1_bd_op(hr_bd_op_type_t, bd_srv_t *, aoff64_t, size_t,
    5959    void *, const void *, size_t);
     60static errno_t hr_raid1_rebuild(void *);
    6061
    6162/* bdops */
     
    132133}
    133134
     135errno_t hr_raid1_add_hotspare(hr_volume_t *vol, service_id_t hotspare)
     136{
     137        HR_DEBUG("hr_raid1_add_hotspare()\n");
     138
     139        fibril_mutex_lock(&vol->lock);
     140
     141        if (vol->hotspare_no >= HR_MAX_HOTSPARES) {
     142                HR_ERROR("hr_raid1_add_hotspare(): cannot add more hotspares "
     143                    "to \"%s\"\n", vol->devname);
     144                fibril_mutex_unlock(&vol->lock);
     145                return ELIMIT;
     146        }
     147
     148        vol->hotspares[vol->hotspare_no].svc_id = hotspare;
     149        vol->hotspares[vol->hotspare_no].status = HR_EXT_HOTSPARE;
     150        vol->hotspare_no++;
     151
     152        /*
     153         * If the volume is degraded, start rebuild right away.
     154         */
     155        if (vol->status == HR_VOL_DEGRADED) {
     156                HR_DEBUG("hr_raid1_add_hotspare(): volume in DEGRADED state, "
     157                    "spawning new rebuild fibril\n");
     158                fid_t fib = fibril_create(hr_raid1_rebuild, vol);
     159                if (fib == 0)
     160                        return EINVAL;
     161                fibril_start(fib);
     162                fibril_detach(fib);
     163        }
     164
     165        fibril_mutex_unlock(&vol->lock);
     166
     167        return EOK;
     168}
     169
    134170static errno_t hr_raid1_bd_open(bd_srvs_t *bds, bd_srv_t *bd)
    135171{
     
    180216{
    181217        if (vol->status == HR_VOL_ONLINE ||
    182             vol->status == HR_VOL_DEGRADED)
     218            vol->status == HR_VOL_DEGRADED ||
     219            vol->status == HR_VOL_REBUILD)
    183220                return EOK;
    184221        return EINVAL;
     
    192229{
    193230        hr_vol_status_t old_state = vol->status;
    194         size_t healthy = 0;
    195         for (size_t i = 0; i < vol->dev_no; i++)
    196                 if (vol->extents[i].status == HR_EXT_ONLINE)
    197                         healthy++;
     231        size_t healthy = hr_count_extents(vol, HR_EXT_ONLINE);
    198232
    199233        if (healthy == 0) {
     
    206240                return EINVAL;
    207241        } else if (healthy < vol->dev_no) {
    208                 if (old_state != HR_VOL_DEGRADED) {
     242                if (old_state != HR_VOL_DEGRADED &&
     243                    old_state != HR_VOL_REBUILD) {
    209244                        HR_WARN("RAID 1 array \"%s\" (%lu) has some "
    210                             "inactive extent(s), marking volume as DEGRADED",
     245                            "unusable extent(s), marking volume as DEGRADED",
    211246                            vol->devname, vol->svc_id);
    212247                        vol->status = HR_VOL_DEGRADED;
     248                        if (vol->hotspare_no > 0) {
     249                                fid_t fib = fibril_create(hr_raid1_rebuild,
     250                                    vol);
     251                                if (fib == 0) {
     252                                        return EINVAL;
     253                                }
     254                                fibril_start(fib);
     255                                fibril_detach(fib);
     256                        }
    213257                }
    214258                return EOK;
     
    309353}
    310354
     355/*
     356 * Put the last HOTSPARE extent in place
     357 * of first DEGRADED, and start the rebuild.
     358 */
     359static errno_t hr_raid1_rebuild(void *arg)
     360{
     361        HR_DEBUG("hr_raid1_rebuild()\n");
     362
     363        hr_volume_t *vol = arg;
     364        void *buf = NULL;
     365        errno_t rc = EOK;
     366
     367        fibril_mutex_lock(&vol->lock);
     368
     369        if (vol->hotspare_no == 0) {
     370                HR_WARN("hr_raid1_rebuild(): no free hotspares on \"%s\", "
     371                    "aborting rebuild\n", vol->devname);
     372                /* retval isn't checked for now */
     373                goto end;
     374        }
     375
     376        size_t bad = vol->dev_no;
     377        for (size_t i = 0; i < vol->dev_no; i++) {
     378                if (vol->extents[i].status == HR_EXT_FAILED) {
     379                        bad = i;
     380                        break;
     381                }
     382        }
     383
     384        if (bad == vol->dev_no) {
     385                HR_WARN("hr_raid1_rebuild(): no bad extent on \"%s\", "
     386                    "aborting rebuild\n", vol->devname);
     387                /* retval isn't checked for now */
     388                goto end;
     389        }
     390
     391        block_fini(vol->extents[bad].svc_id);
     392
     393        size_t hotspare_idx = vol->hotspare_no - 1;
     394
     395        vol->extents[bad].svc_id = vol->hotspares[hotspare_idx].svc_id;
     396        hr_update_ext_status(vol, bad, HR_EXT_REBUILD);
     397
     398        vol->hotspares[hotspare_idx].svc_id = 0;
     399        vol->hotspares[hotspare_idx].status = HR_EXT_MISSING;
     400        vol->hotspare_no--;
     401
     402        HR_WARN("hr_raid1_rebuild(): changing volume \"%s\" (%lu) state "
     403            "from %s to %s\n", vol->devname, vol->svc_id,
     404            hr_get_vol_status_msg(vol->status),
     405            hr_get_vol_status_msg(HR_VOL_REBUILD));
     406        vol->status = HR_VOL_REBUILD;
     407
     408        hr_extent_t *hotspare = &vol->extents[bad];
     409
     410        HR_DEBUG("hr_raid1_rebuild(): initing (%lu)\n", hotspare->svc_id);
     411
     412        rc = block_init(hotspare->svc_id);
     413        if (rc != EOK) {
     414                HR_ERROR("hr_raid1_rebuild(): initing (%lu) failed, "
     415                    "aborting rebuild\n", hotspare->svc_id);
     416                goto end;
     417        }
     418
     419        size_t left = vol->data_blkno;
     420        size_t max_blks = DATA_XFER_LIMIT / vol->bsize;
     421        buf = malloc(max_blks * vol->bsize);
     422
     423        hr_extent_t *ext;
     424        size_t rebuild_ext_idx = bad;
     425
     426        size_t cnt;
     427        uint64_t ba = 0;
     428        hr_add_ba_offset(vol, &ba);
     429        while (left != 0) {
     430                cnt = min(max_blks, left);
     431                for (size_t i = 0; i < vol->dev_no; i++) {
     432                        ext = &vol->extents[i];
     433                        if (ext->status == HR_EXT_ONLINE) {
     434                                rc = block_read_direct(ext->svc_id, ba, cnt,
     435                                    buf);
     436                                if (rc != EOK) {
     437                                        handle_extent_error(vol, i, rc);
     438                                        if (i + 1 < vol->dev_no) {
     439                                                /* still might have one ONLINE */
     440                                                continue;
     441                                        } else {
     442                                                HR_ERROR("rebuild on \"%s\" (%lu), failed due to "
     443                                                    "too many failed extents\n",
     444                                                    vol->devname, vol->svc_id);
     445                                                goto end;
     446                                        }
     447                                }
     448                                break;
     449                        }
     450                }
     451
     452                rc = block_write_direct(hotspare->svc_id, ba, cnt, buf);
     453                if (rc != EOK) {
     454                        handle_extent_error(vol, rebuild_ext_idx, rc);
     455                        HR_ERROR("rebuild on \"%s\" (%lu), extent number %lu\n",
     456                            vol->devname, vol->svc_id, rebuild_ext_idx);
     457                        goto end;
     458
     459                }
     460
     461                ba += cnt;
     462                left -= cnt;
     463        }
     464
     465        HR_DEBUG("hr_raid1_rebuild(): rebuild finished on \"%s\" (%lu), "
     466            "extent number %lu\n", vol->devname, vol->svc_id, hotspare_idx);
     467
     468        hr_update_ext_status(vol, hotspare_idx, HR_EXT_ONLINE);
     469        /*
     470         * For now write metadata at the end, because
     471         * we don't sync metada accross extents yet.
     472         */
     473        hr_write_meta_to_ext(vol, bad);
     474end:
     475        (void) hr_raid1_update_vol_status(vol);
     476
     477        fibril_mutex_unlock(&vol->lock);
     478
     479        if (buf != NULL)
     480                free(buf);
     481
     482        /* retval isn't checked anywhere for now */
     483        return rc;
     484}
     485
    311486/** @}
    312487 */
  • uspace/srv/bd/hr/var.h

    r06f2762 r5b320ac  
    5151        errno_t (*init)(hr_volume_t *);
    5252        void    (*status_event)(hr_volume_t *);
     53        errno_t (*add_hotspare)(hr_volume_t *, service_id_t);
    5354} hr_ops_t;
    5455
     
    5657        hr_ops_t hr_ops;
    5758        bd_srvs_t hr_bds;
     59
    5860        link_t lvolumes;
    5961        fibril_mutex_t lock;
    60         char devname[HR_DEVNAME_LEN];
     62
     63        size_t dev_no;
    6164        hr_extent_t extents[HR_MAX_EXTENTS];
     65
     66        size_t hotspare_no;
     67        hr_extent_t hotspares[HR_MAX_EXTENTS];
     68
     69        size_t bsize;
    6270        uint64_t nblocks;
    6371        uint64_t data_blkno;
    6472        uint32_t data_offset; /* in blocks */
    6573        uint32_t strip_size;
     74
    6675        service_id_t svc_id;
    67         size_t bsize;
    68         size_t dev_no;
     76        hr_vol_status_t status;
    6977        hr_level_t level;
    70         hr_vol_status_t status;
     78        char devname[HR_DEVNAME_LEN];
    7179} hr_volume_t;
    7280
     
    95103extern void hr_raid5_status_event(hr_volume_t *);
    96104
     105extern errno_t hr_raid1_add_hotspare(hr_volume_t *, service_id_t);
     106
    97107#endif
    98108
Note: See TracChangeset for help on using the changeset viewer.