Changeset 5b320ac in mainline for uspace/srv
- Timestamp:
- 2024-11-22T18:38:49Z (11 months ago)
- Children:
- d0f0744
- Parents:
- 06f2762
- Location:
- uspace/srv/bd/hr
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
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.