Changeset 5b320ac in mainline
- Timestamp:
- 2024-11-22T18:38:49Z (7 months ago)
- Children:
- d0f0744
- Parents:
- 06f2762
- Location:
- uspace
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/app/hrctl/hrctl.c
r06f2762 r5b320ac 69 69 " -4 parity on one extent\n" 70 70 " -5 distributed parity\n" 71 " -H, --hotspare=DEV add hotspare extent\n" 71 72 "\n" 72 73 "When specifying name for creation or assembly, the device name\n" … … 80 81 " - assembles RAID device named /hr0 consisting of 2 drives,\n" 81 82 " that were previously in an array\n" 83 " hrctl devices/hr0 --hotspare=devices/disk10\n" 84 " - adds \"devices/disk10\" as hotspare extent\n" 82 85 "Limitations:\n" 83 86 " - device name must be less than 32 characters in size\n"; … … 93 96 { "destroy", required_argument, 0, 'D' }, 94 97 { "fail-extent", required_argument, 0, 'F' }, 98 { "hotspare", required_argument, 0, 'H' }, 95 99 { 0, 0, 0, 0 } 96 100 }; … … 247 251 248 252 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:", 250 254 long_options, NULL); 251 255 switch (c) { … … 345 349 } 346 350 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; 347 382 } 348 383 } -
uspace/lib/device/include/hr.h
r06f2762 r5b320ac 43 43 /* for now */ 44 44 #define HR_MAX_EXTENTS 4 45 #define HR_MAX_HOTSPARES HR_MAX_EXTENTS 45 46 46 47 #define HR_DEVNAME_LEN 32 … … 57 58 HR_VOL_ONLINE, /* OK, OPTIMAL */ 58 59 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 60 62 } hr_vol_status_t; 61 63 … … 63 65 HR_EXT_ONLINE, /* OK */ 64 66 HR_EXT_MISSING, 65 HR_EXT_FAILED 67 HR_EXT_FAILED, 68 HR_EXT_REBUILD, 69 HR_EXT_HOTSPARE 66 70 } hr_ext_status_t; 67 71 … … 84 88 typedef struct hr_vol_info { 85 89 hr_extent_t extents[HR_MAX_EXTENTS]; 90 hr_extent_t hotspares[HR_MAX_HOTSPARES]; 86 91 size_t extent_no; 92 size_t hotspare_no; 87 93 service_id_t svc_id; 88 94 hr_level_t level; … … 98 104 extern errno_t hr_create(hr_t *, hr_config_t *, bool); 99 105 extern errno_t hr_stop(const char *, long); 106 extern errno_t hr_add_hotspare(service_id_t, service_id_t); 100 107 extern errno_t hr_print_status(void); 101 108 -
uspace/lib/device/include/ipc/hr.h
r06f2762 r5b320ac 42 42 HR_ASSEMBLE, 43 43 HR_STOP, 44 HR_ADD_HOTSPARE, 44 45 HR_STATUS 45 46 } hr_request_t; -
uspace/lib/device/src/hr.c
r06f2762 r5b320ac 166 166 printf(" %s %zu %s\n", hr_get_ext_status_msg(ext->status), i, devname); 167 167 } 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 168 186 return EOK; 169 187 } … … 194 212 if (rc != EOK) 195 213 goto error; 214 error: 215 hr_sess_destroy(hr); 216 return rc; 217 } 218 219 errno_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); 196 237 error: 197 238 hr_sess_destroy(hr); … … 277 318 case HR_VOL_DEGRADED: 278 319 return "DEGRADED"; 320 case HR_VOL_REBUILD: 321 return "REBUILD"; 279 322 default: 280 323 return "UNKNOWN"; … … 291 334 case HR_EXT_FAILED: 292 335 return "FAILED"; 336 case HR_EXT_REBUILD: 337 return "REBUILD"; 338 case HR_EXT_HOTSPARE: 339 return "HOTSPARE"; 293 340 default: 294 341 return "UNKNOWN"; -
uspace/srv/bd/hr/hr.c
r06f2762 r5b320ac 191 191 new_volume->hr_ops.init = hr_raid1_init; 192 192 new_volume->hr_ops.status_event = hr_raid1_status_event; 193 new_volume->hr_ops.add_hotspare = hr_raid1_add_hotspare; 193 194 break; 194 195 case HR_LVL_0: … … 287 288 } 288 289 290 static 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 289 320 static void hr_print_status_srv(ipc_call_t *icall) 290 321 { … … 318 349 memcpy(info.extents, vol->extents, 319 350 sizeof(hr_extent_t) * HR_MAX_EXTENTS); 351 memcpy(info.hotspares, vol->hotspares, 352 sizeof(hr_extent_t) * HR_MAX_HOTSPARES); 320 353 info.svc_id = vol->svc_id; 321 354 info.extent_no = vol->dev_no; 355 info.hotspare_no = vol->hotspare_no; 322 356 info.level = vol->level; 323 357 /* print usable number of blocks */ … … 377 411 hr_stop_srv(&call); 378 412 break; 413 case HR_ADD_HOTSPARE: 414 hr_add_hotspare_srv(&call); 415 break; 379 416 case HR_STATUS: 380 417 hr_print_status_srv(&call); -
uspace/srv/bd/hr/raid1.c
r06f2762 r5b320ac 58 58 static errno_t hr_raid1_bd_op(hr_bd_op_type_t, bd_srv_t *, aoff64_t, size_t, 59 59 void *, const void *, size_t); 60 static errno_t hr_raid1_rebuild(void *); 60 61 61 62 /* bdops */ … … 132 133 } 133 134 135 errno_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 134 170 static errno_t hr_raid1_bd_open(bd_srvs_t *bds, bd_srv_t *bd) 135 171 { … … 180 216 { 181 217 if (vol->status == HR_VOL_ONLINE || 182 vol->status == HR_VOL_DEGRADED) 218 vol->status == HR_VOL_DEGRADED || 219 vol->status == HR_VOL_REBUILD) 183 220 return EOK; 184 221 return EINVAL; … … 192 229 { 193 230 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); 198 232 199 233 if (healthy == 0) { … … 206 240 return EINVAL; 207 241 } 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) { 209 244 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", 211 246 vol->devname, vol->svc_id); 212 247 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 } 213 257 } 214 258 return EOK; … … 309 353 } 310 354 355 /* 356 * Put the last HOTSPARE extent in place 357 * of first DEGRADED, and start the rebuild. 358 */ 359 static 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); 474 end: 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 311 486 /** @} 312 487 */ -
uspace/srv/bd/hr/var.h
r06f2762 r5b320ac 51 51 errno_t (*init)(hr_volume_t *); 52 52 void (*status_event)(hr_volume_t *); 53 errno_t (*add_hotspare)(hr_volume_t *, service_id_t); 53 54 } hr_ops_t; 54 55 … … 56 57 hr_ops_t hr_ops; 57 58 bd_srvs_t hr_bds; 59 58 60 link_t lvolumes; 59 61 fibril_mutex_t lock; 60 char devname[HR_DEVNAME_LEN]; 62 63 size_t dev_no; 61 64 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; 62 70 uint64_t nblocks; 63 71 uint64_t data_blkno; 64 72 uint32_t data_offset; /* in blocks */ 65 73 uint32_t strip_size; 74 66 75 service_id_t svc_id; 67 size_t bsize; 68 size_t dev_no; 76 hr_vol_status_t status; 69 77 hr_level_t level; 70 hr_vol_status_t status;78 char devname[HR_DEVNAME_LEN]; 71 79 } hr_volume_t; 72 80 … … 95 103 extern void hr_raid5_status_event(hr_volume_t *); 96 104 105 extern errno_t hr_raid1_add_hotspare(hr_volume_t *, service_id_t); 106 97 107 #endif 98 108
Note:
See TracChangeset
for help on using the changeset viewer.