Fix pool creation with feature@allocation_classes disabled

When "feature@allocation_classes" is not enabled on the pool no vdev
with "special" or "dedup" allocation type should be allowed to exist in
the vdev tree.

Reviewed-by: Pavel Zakharov <pavel.zakharov@delphix.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: loli10K <ezomori.nozomu@gmail.com>
Closes #9427 
Closes #9429
This commit is contained in:
loli10K 2019-10-11 01:39:41 +02:00 committed by Brian Behlendorf
parent 2516a87821
commit 715c996d3b
4 changed files with 44 additions and 1 deletions

View File

@ -34,6 +34,7 @@ extern "C" {
#endif
extern boolean_t zfs_allocatable_devs(nvlist_t *);
extern boolean_t zfs_special_devs(nvlist_t *);
extern void zpool_get_load_policy(nvlist_t *, zpool_load_policy_t *);
extern int zfs_zpl_version_map(int spa_version);

View File

@ -64,6 +64,33 @@ zfs_allocatable_devs(nvlist_t *nv)
return (B_FALSE);
}
/*
* Are there special vdevs?
*/
boolean_t
zfs_special_devs(nvlist_t *nv)
{
char *bias;
uint_t c;
nvlist_t **child;
uint_t children;
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
&child, &children) != 0) {
return (B_FALSE);
}
for (c = 0; c < children; c++) {
if (nvlist_lookup_string(child[c], ZPOOL_CONFIG_ALLOCATION_BIAS,
&bias) == 0) {
if (strcmp(bias, VDEV_ALLOC_BIAS_SPECIAL) == 0 ||
strcmp(bias, VDEV_ALLOC_BIAS_DEDUP) == 0) {
return (B_TRUE);
}
}
}
return (B_FALSE);
}
void
zpool_get_load_policy(nvlist_t *nvl, zpool_load_policy_t *zlpp)
{
@ -223,6 +250,7 @@ zfs_dataset_name_hidden(const char *name)
#if defined(_KERNEL)
EXPORT_SYMBOL(zfs_allocatable_devs);
EXPORT_SYMBOL(zfs_special_devs);
EXPORT_SYMBOL(zpool_get_load_policy);
EXPORT_SYMBOL(zfs_zpl_version_map);
EXPORT_SYMBOL(zfs_spa_version_map);

View File

@ -5620,6 +5620,7 @@ spa_create(const char *pool, nvlist_t *nvroot, nvlist_t *props,
uint64_t version, obj;
boolean_t has_features;
boolean_t has_encryption;
boolean_t has_allocclass;
spa_feature_t feat;
char *feat_name;
char *poolname;
@ -5664,6 +5665,7 @@ spa_create(const char *pool, nvlist_t *nvroot, nvlist_t *props,
has_features = B_FALSE;
has_encryption = B_FALSE;
has_allocclass = B_FALSE;
for (nvpair_t *elem = nvlist_next_nvpair(props, NULL);
elem != NULL; elem = nvlist_next_nvpair(props, elem)) {
if (zpool_prop_feature(nvpair_name(elem))) {
@ -5673,6 +5675,8 @@ spa_create(const char *pool, nvlist_t *nvroot, nvlist_t *props,
VERIFY0(zfeature_lookup_name(feat_name, &feat));
if (feat == SPA_FEATURE_ENCRYPTION)
has_encryption = B_TRUE;
if (feat == SPA_FEATURE_ALLOCATION_CLASSES)
has_allocclass = B_TRUE;
}
}
@ -5686,6 +5690,12 @@ spa_create(const char *pool, nvlist_t *nvroot, nvlist_t *props,
return (error);
}
}
if (!has_allocclass && zfs_special_devs(nvroot)) {
spa_deactivate(spa);
spa_remove(spa);
mutex_exit(&spa_namespace_lock);
return (ENOTSUP);
}
if (has_features || nvlist_lookup_uint64(props,
zpool_prop_to_name(ZPOOL_PROP_VERSION), &version) != 0) {

View File

@ -20,7 +20,8 @@
#
# DESCRIPTION:
# Creating a pool with a special device succeeds.
# Creating a pool with a special device succeeds, but only if
# "feature@allocation_classes" is enabled.
#
verify_runnable "global"
@ -31,6 +32,9 @@ log_assert $claim
log_onexit cleanup
log_must disk_setup
for type in special dedup; do
log_mustnot zpool create -d $TESTPOOL $CLASS_DISK0 $type $CLASS_DISK1
done
log_must zpool create $TESTPOOL raidz $ZPOOL_DISKS special mirror \
$CLASS_DISK0 $CLASS_DISK1
log_must display_status "$TESTPOOL"