Skip to content

Commit

Permalink
Attaching a vdev while resilver/scrub is running causes panic.
Browse files Browse the repository at this point in the history
  • Loading branch information
skiselkov committed Feb 9, 2017
1 parent 1277469 commit 2f86f9c
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 2 deletions.
25 changes: 25 additions & 0 deletions usr/src/uts/common/fs/zfs/dsl_scan.c
Original file line number Diff line number Diff line change
Expand Up @@ -2799,6 +2799,30 @@ dsl_scan_io_queue_destroy(dsl_scan_io_queue_t *queue)
cv_destroy(&queue->q_cv);
}

/*
* Properly transfers a dsl_scan_queue_t from `svd' to `tvd'. This is
* called on behalf of vdev_top_transfer when creating or destroying
* a mirror vdev due to zpool attach/detach.
*/
void
dsl_scan_io_queue_vdev_xfer(vdev_t *svd, vdev_t *tvd)
{
mutex_enter(&svd->vdev_scan_io_queue_lock);
mutex_enter(&tvd->vdev_scan_io_queue_lock);

VERIFY3P(tvd->vdev_scan_io_queue, ==, NULL);
tvd->vdev_scan_io_queue = svd->vdev_scan_io_queue;
svd->vdev_scan_io_queue = NULL;
if (tvd->vdev_scan_io_queue != NULL) {
tvd->vdev_scan_io_queue->q_vd = tvd;
range_tree_set_lock(tvd->vdev_scan_io_queue->q_exts_by_addr,
&tvd->vdev_scan_io_queue_lock);
}

mutex_exit(&tvd->vdev_scan_io_queue_lock);
mutex_exit(&svd->vdev_scan_io_queue_lock);
}

static void
scan_io_queues_destroy(dsl_scan_t *scn)
{
Expand Down Expand Up @@ -3157,6 +3181,7 @@ scan_io_queues_run(dsl_scan_t *scn)
spa->spa_root_vdev->vdev_children;

ASSERT(scn->scn_is_sorted);
ASSERT(spa_config_held(spa, SCL_CONFIG, RW_READER));

if (scn->scn_taskq == NULL) {
char *tq_name = kmem_zalloc(ZFS_MAX_DATASET_NAME_LEN + 16,
Expand Down
12 changes: 12 additions & 0 deletions usr/src/uts/common/fs/zfs/range_tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,18 @@ range_tree_set_gap(range_tree_t *rt, uint64_t gap)
rt->rt_gap = gap;
}

/*
* Changes out the lock used by the range tree. Useful when you are moving
* the range tree between containing structures without having to recreate
* it. Both the old and new locks must be held by the caller.
*/
void
range_tree_set_lock(range_tree_t *rt, kmutex_t *lp)
{
ASSERT(MUTEX_HELD(rt->rt_lock) && MUTEX_HELD(lp));
rt->rt_lock = lp;
}

static void
range_tree_stat_incr(range_tree_t *rt, range_seg_t *rs)
{
Expand Down
1 change: 1 addition & 0 deletions usr/src/uts/common/fs/zfs/sys/dsl_scan.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ void dsl_scan_ds_clone_swapped(struct dsl_dataset *ds1, struct dsl_dataset *ds2,
boolean_t dsl_scan_active(dsl_scan_t *scn);
void dsl_scan_freed(spa_t *spa, const blkptr_t *bp);
void dsl_scan_io_queue_destroy(dsl_scan_io_queue_t *queue);
void dsl_scan_io_queue_vdev_xfer(vdev_t *svd, vdev_t *tvd);

#ifdef __cplusplus
}
Expand Down
1 change: 1 addition & 0 deletions usr/src/uts/common/fs/zfs/sys/range_tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ void range_tree_verify(range_tree_t *rt, uint64_t start, uint64_t size);
void range_tree_swap(range_tree_t **rtsrc, range_tree_t **rtdst);
void range_tree_stat_verify(range_tree_t *rt);
void range_tree_set_gap(range_tree_t *rt, uint64_t gap);
void range_tree_set_lock(range_tree_t *rt, kmutex_t *lp);

void range_tree_add(void *arg, uint64_t start, uint64_t size);
void range_tree_remove(void *arg, uint64_t start, uint64_t size);
Expand Down
3 changes: 1 addition & 2 deletions usr/src/uts/common/fs/zfs/vdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -770,8 +770,7 @@ vdev_top_transfer(vdev_t *svd, vdev_t *tvd)
tvd->vdev_islog = svd->vdev_islog;
svd->vdev_islog = 0;

tvd->vdev_scan_io_queue = svd->vdev_scan_io_queue;
svd->vdev_scan_io_queue = NULL;
dsl_scan_io_queue_vdev_xfer(svd, tvd);
}

static void
Expand Down

0 comments on commit 2f86f9c

Please sign in to comment.