diff options
Diffstat (limited to 'module/zfs/vdev_removal.c')
-rw-r--r-- | module/zfs/vdev_removal.c | 38 |
1 files changed, 32 insertions, 6 deletions
diff --git a/module/zfs/vdev_removal.c b/module/zfs/vdev_removal.c index dcce93c70..9db6fe37b 100644 --- a/module/zfs/vdev_removal.c +++ b/module/zfs/vdev_removal.c @@ -21,7 +21,7 @@ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2011, 2017 by Delphix. All rights reserved. + * Copyright (c) 2011, 2018 by Delphix. All rights reserved. */ #include <sys/zfs_context.h> @@ -944,8 +944,18 @@ spa_vdev_copy_segment(vdev_t *vd, range_tree_t *segs, } ASSERT3U(size, <=, maxalloc); - int error = metaslab_alloc_dva(spa, mg->mg_class, size, - &dst, 0, NULL, txg, 0, zal, 0); + /* + * An allocation class might not have any remaining vdevs or space + */ + metaslab_class_t *mc = mg->mg_class; + if (mc != spa_normal_class(spa) && mc->mc_groups <= 1) + mc = spa_normal_class(spa); + int error = metaslab_alloc_dva(spa, mc, size, &dst, 0, NULL, txg, 0, + zal, 0); + if (error == ENOSPC && mc != spa_normal_class(spa)) { + error = metaslab_alloc_dva(spa, spa_normal_class(spa), size, + &dst, 0, NULL, txg, 0, zal, 0); + } if (error != 0) return (error); @@ -1853,15 +1863,31 @@ spa_vdev_remove_top_check(vdev_t *vd) if (!spa_feature_is_enabled(spa, SPA_FEATURE_DEVICE_REMOVAL)) return (SET_ERROR(ENOTSUP)); + /* available space in the pool's normal class */ + uint64_t available = dsl_dir_space_available( + spa->spa_dsl_pool->dp_root_dir, NULL, 0, B_TRUE); + + metaslab_class_t *mc = vd->vdev_mg->mg_class; + + /* + * When removing a vdev from an allocation class that has + * remaining vdevs, include available space from the class. + */ + if (mc != spa_normal_class(spa) && mc->mc_groups > 1) { + uint64_t class_avail = metaslab_class_get_space(mc) - + metaslab_class_get_alloc(mc); + + /* add class space, adjusted for overhead */ + available += (class_avail * 94) / 100; + } + /* * There has to be enough free space to remove the * device and leave double the "slop" space (i.e. we * must leave at least 3% of the pool free, in addition to * the normal slop space). */ - if (dsl_dir_space_available(spa->spa_dsl_pool->dp_root_dir, - NULL, 0, B_TRUE) < - vd->vdev_stat.vs_dspace + spa_get_slop_space(spa)) { + if (available < vd->vdev_stat.vs_dspace + spa_get_slop_space(spa)) { return (SET_ERROR(ENOSPC)); } |