* The removal thread operates in open context. It iterates over all * allocated space in the vdev, by loading each metaslab's spacemap. * For each contiguous segment of allocated space (capping the segment * size at SPA_MAXBLOCKSIZE), we: * - Allocate space for it on another vdev. * - Create a new mapping from the old location to the new location * (as a record in svr_new_segment
| 1404 | * (see vdev_mapping_sync()). |
| 1405 | */ |
| 1406 | static void |
| 1407 | spa_vdev_remove_thread(void *arg) |
| 1408 | { |
| 1409 | spa_t *spa = arg; |
| 1410 | spa_vdev_removal_t *svr = spa->spa_vdev_removal; |
| 1411 | vdev_copy_arg_t vca; |
| 1412 | uint64_t max_alloc = spa_remove_max_segment(spa); |
| 1413 | uint64_t last_txg = 0; |
| 1414 | |
| 1415 | spa_config_enter(spa, SCL_CONFIG, FTAG, RW_READER); |
| 1416 | vdev_t *vd = vdev_lookup_top(spa, svr->svr_vdev_id); |
| 1417 | vdev_indirect_mapping_t *vim = vd->vdev_indirect_mapping; |
| 1418 | uint64_t start_offset = vdev_indirect_mapping_max_offset(vim); |
| 1419 | |
| 1420 | ASSERT3P(vd->vdev_ops, !=, &vdev_indirect_ops); |
| 1421 | ASSERT(vdev_is_concrete(vd)); |
| 1422 | ASSERT(vd->vdev_removing); |
| 1423 | ASSERT(vd->vdev_indirect_config.vic_mapping_object != 0); |
| 1424 | ASSERT(vim != NULL); |
| 1425 | |
| 1426 | mutex_init(&vca.vca_lock, NULL, MUTEX_DEFAULT, NULL); |
| 1427 | cv_init(&vca.vca_cv, NULL, CV_DEFAULT, NULL); |
| 1428 | vca.vca_outstanding_bytes = 0; |
| 1429 | vca.vca_read_error_bytes = 0; |
| 1430 | vca.vca_write_error_bytes = 0; |
| 1431 | |
| 1432 | mutex_enter(&svr->svr_lock); |
| 1433 | |
| 1434 | /* |
| 1435 | * Start from vim_max_offset so we pick up where we left off |
| 1436 | * if we are restarting the removal after opening the pool. |
| 1437 | */ |
| 1438 | uint64_t msi; |
| 1439 | for (msi = start_offset >> vd->vdev_ms_shift; |
| 1440 | msi < vd->vdev_ms_count && !svr->svr_thread_exit; msi++) { |
| 1441 | metaslab_t *msp = vd->vdev_ms[msi]; |
| 1442 | ASSERT3U(msi, <=, vd->vdev_ms_count); |
| 1443 | |
| 1444 | ASSERT0(range_tree_space(svr->svr_allocd_segs)); |
| 1445 | |
| 1446 | mutex_enter(&msp->ms_sync_lock); |
| 1447 | mutex_enter(&msp->ms_lock); |
| 1448 | |
| 1449 | /* |
| 1450 | * Assert nothing in flight -- ms_*tree is empty. |
| 1451 | */ |
| 1452 | for (int i = 0; i < TXG_SIZE; i++) { |
| 1453 | ASSERT0(range_tree_space(msp->ms_allocating[i])); |
| 1454 | } |
| 1455 | |
| 1456 | /* |
| 1457 | * If the metaslab has ever been allocated from (ms_sm!=NULL), |
| 1458 | * read the allocated segments from the space map object |
| 1459 | * into svr_allocd_segs. Since we do this while holding |
| 1460 | * svr_lock and ms_sync_lock, concurrent frees (which |
| 1461 | * would have modified the space map) will wait for us |
| 1462 | * to finish loading the spacemap, and then take the |
| 1463 | * appropriate action (see free_from_removing_vdev()). |
nothing calls this directly
no test coverage detected