Fix vdev_initialize_restart / removal race

Resolve a vdev_initialize crash uncovered by ztest.  Similar
to when starting a new initialization verify that a removal
is not in progress.  Additionally, do not restart when the
thread already exists.  This check is now congruent with the
POOL_INITIALIZE_DO handling in spa_vdev_initialize_impl().

Reviewed-by: Tom Caputi <tcaputi@datto.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #8477
This commit is contained in:
Brian Behlendorf 2019-03-12 10:39:47 -07:00 committed by GitHub
parent 3d31aad83e
commit dd785b5b86
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -68,7 +68,7 @@ vdev_initialize_zap_update_sync(void *arg, dmu_tx_t *tx)
* We pass in the guid instead of the vdev_t since the vdev may * We pass in the guid instead of the vdev_t since the vdev may
* have been freed prior to the sync task being processed. This * have been freed prior to the sync task being processed. This
* happens when a vdev is detached as we call spa_config_vdev_exit(), * happens when a vdev is detached as we call spa_config_vdev_exit(),
* stop the intializing thread, schedule the sync task, and free * stop the initializing thread, schedule the sync task, and free
* the vdev. Later when the scheduled sync task is invoked, it would * the vdev. Later when the scheduled sync task is invoked, it would
* find that the vdev has been freed. * find that the vdev has been freed.
*/ */
@ -838,7 +838,9 @@ vdev_initialize_restart(vdev_t *vd)
/* load progress for reporting, but don't resume */ /* load progress for reporting, but don't resume */
VERIFY0(vdev_initialize_load(vd)); VERIFY0(vdev_initialize_load(vd));
} else if (vd->vdev_initialize_state == } else if (vd->vdev_initialize_state ==
VDEV_INITIALIZE_ACTIVE && vdev_writeable(vd)) { VDEV_INITIALIZE_ACTIVE && vdev_writeable(vd) &&
!vd->vdev_top->vdev_removing &&
vd->vdev_initialize_thread == NULL) {
vdev_initialize(vd); vdev_initialize(vd);
} }