Changeset 5b320ac in mainline


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

hr: hotspares + RAID1 rebuild

Location:
uspace
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • uspace/app/hrctl/hrctl.c

    r06f2762 r5b320ac  
    6969    "  -4                        parity on one extent\n"
    7070    "  -5                        distributed parity\n"
     71    "  -H, --hotspare=DEV        add hotspare extent\n"
    7172    "\n"
    7273    "When specifying name for creation or assembly, the device name\n"
     
    8081    "    - assembles RAID device named /hr0 consisting of 2 drives,\n"
    8182    "      that were previously in an array\n"
     83    "  hrctl devices/hr0 --hotspare=devices/disk10\n"
     84    "    - adds \"devices/disk10\" as hotspare extent\n"
    8285    "Limitations:\n"
    8386    "  - device name must be less than 32 characters in size\n";
     
    9396        { "destroy", required_argument, 0, 'D' },
    9497        { "fail-extent", required_argument, 0, 'F' },
     98        { "hotspare", required_argument, 0, 'H' },
    9599        { 0, 0, 0, 0 }
    96100};
     
    247251
    248252        while (c != -1) {
    249                 c = getopt_long(argc, argv, "hsC:c:A:a:l:0145Ln:D:F:",
     253                c = getopt_long(argc, argv, "hsC:c:A:a:l:0145Ln:D:F:H:",
    250254                    long_options, NULL);
    251255                switch (c) {
     
    345349                        }
    346350                        break;
     351                case 'H':
     352                        if (optind != 3 && argc != 4)
     353                                goto bad;
     354
     355                        service_id_t hotspare;
     356                        service_id_t vol_svc_id;
     357
     358                        rc = loc_service_get_id(argv[1], &vol_svc_id, 0);
     359                        if (rc != EOK) {
     360                                printf("hrctl: error resolving volume \"%s\", "
     361                                    "aborting extent addition\n", argv[1]);
     362                                goto bad;
     363                        }
     364
     365                        rc = loc_service_get_id(optarg, &hotspare, 0);
     366                        if (rc != EOK) {
     367                                printf("hrctl: error resolving device \"%s\", "
     368                                    "aborting extent addition\n", optarg);
     369                                goto bad;
     370                        }
     371
     372                        rc = hr_add_hotspare(vol_svc_id, hotspare);
     373                        if (rc != EOK)
     374                                printf("hrctl: hr_add_hotspare() rc: %s\n",
     375                                    str_error(rc));
     376
     377                        free(cfg);
     378                        if (rc != EOK)
     379                                return 1;
     380                        else
     381                                return 0;
    347382                }
    348383        }
  • uspace/lib/device/include/hr.h

    r06f2762 r5b320ac  
    4343/* for now */
    4444#define HR_MAX_EXTENTS 4
     45#define HR_MAX_HOTSPARES HR_MAX_EXTENTS
    4546
    4647#define HR_DEVNAME_LEN 32
     
    5758        HR_VOL_ONLINE,  /* OK, OPTIMAL */
    5859        HR_VOL_FAULTY,
    59         HR_VOL_DEGRADED /* also used for partial, but usable mirror */
     60        HR_VOL_DEGRADED, /* also used for partial, but usable mirror */
     61        HR_VOL_REBUILD
    6062} hr_vol_status_t;
    6163
     
    6365        HR_EXT_ONLINE,  /* OK */
    6466        HR_EXT_MISSING,
    65         HR_EXT_FAILED
     67        HR_EXT_FAILED,
     68        HR_EXT_REBUILD,
     69        HR_EXT_HOTSPARE
    6670} hr_ext_status_t;
    6771
     
    8488typedef struct hr_vol_info {
    8589        hr_extent_t extents[HR_MAX_EXTENTS];
     90        hr_extent_t hotspares[HR_MAX_HOTSPARES];
    8691        size_t extent_no;
     92        size_t hotspare_no;
    8793        service_id_t svc_id;
    8894        hr_level_t level;
     
    98104extern errno_t hr_create(hr_t *, hr_config_t *, bool);
    99105extern errno_t hr_stop(const char *, long);
     106extern errno_t hr_add_hotspare(service_id_t, service_id_t);
    100107extern errno_t hr_print_status(void);
    101108
  • uspace/lib/device/include/ipc/hr.h

    r06f2762 r5b320ac  
    4242        HR_ASSEMBLE,
    4343        HR_STOP,
     44        HR_ADD_HOTSPARE,
    4445        HR_STATUS
    4546} hr_request_t;
  • uspace/lib/device/src/hr.c

    r06f2762 r5b320ac  
    166166                        printf("          %s    %zu       %s\n", hr_get_ext_status_msg(ext->status), i, devname);
    167167        }
     168
     169        if (vol_info->hotspare_no == 0)
     170                return EOK;
     171
     172        printf("hotspares: [status] [index] [devname]\n");
     173        for (i = 0; i < vol_info->hotspare_no; i++) {
     174                ext = &vol_info->hotspares[i];
     175                if (ext->status == HR_EXT_MISSING) {
     176                        devname = (char *) "MISSING-devname";
     177                } else {
     178                        rc = loc_service_get_name(ext->svc_id, &devname);
     179                        if (rc != EOK)
     180                                return rc;
     181                }
     182                printf("            %s   %zu     %s\n",
     183                    hr_get_ext_status_msg(ext->status), i, devname);
     184        }
     185
    168186        return EOK;
    169187}
     
    194212        if (rc != EOK)
    195213                goto error;
     214error:
     215        hr_sess_destroy(hr);
     216        return rc;
     217}
     218
     219errno_t hr_add_hotspare(service_id_t vol_svc_id, service_id_t hs_svc_id)
     220{
     221        hr_t *hr;
     222        errno_t rc;
     223        async_exch_t *exch;
     224
     225        rc = hr_sess_init(&hr);
     226        if (rc != EOK)
     227                return rc;
     228
     229        exch = async_exchange_begin(hr->sess);
     230        if (exch == NULL) {
     231                rc = EINVAL;
     232                goto error;
     233        }
     234
     235        rc = async_req_2_0(exch, HR_ADD_HOTSPARE, vol_svc_id, hs_svc_id);
     236        async_exchange_end(exch);
    196237error:
    197238        hr_sess_destroy(hr);
     
    277318        case HR_VOL_DEGRADED:
    278319                return "DEGRADED";
     320        case HR_VOL_REBUILD:
     321                return "REBUILD";
    279322        default:
    280323                return "UNKNOWN";
     
    291334        case HR_EXT_FAILED:
    292335                return "FAILED";
     336        case HR_EXT_REBUILD:
     337                return "REBUILD";
     338        case HR_EXT_HOTSPARE:
     339                return "HOTSPARE";
    293340        default:
    294341                return "UNKNOWN";
  • 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.