Cleanup allocation class selection

- For multilevel gang blocks it seemed possible to fallback from
normal to special class, since they don't have proper object type,
and DMU_OT_NONE is a "metadata".  They should never fallback.
 - Fix possible inversion with zfs_user_indirect_is_special = 0,
when indirects written to normal vdev, while small data to special.
Make small indirect blocks also follow special_small_blocks there.
 - With special_small_blocks now applying to both files and ZVOLs,
make it apply to all non-metadata without extra checks, since there
are no other non-metadata types.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Alexander Motin <alexander.motin@TrueNAS.com>
Closes #18208
This commit is contained in:
Alexander Motin 2026-02-16 10:33:21 -05:00 committed by GitHub
parent cdf89f413c
commit ba970eb202
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 17 additions and 29 deletions

View File

@ -2517,9 +2517,7 @@ dmu_write_policy(objset_t *os, dnode_t *dn, int level, int wp, zio_prop_t *zp)
memset(zp->zp_salt, 0, ZIO_DATA_SALT_LEN);
memset(zp->zp_iv, 0, ZIO_DATA_IV_LEN);
memset(zp->zp_mac, 0, ZIO_DATA_MAC_LEN);
zp->zp_zpl_smallblk = (DMU_OT_IS_FILE(zp->zp_type) ||
zp->zp_type == DMU_OT_ZVOL) ?
os->os_zpl_special_smallblock : 0;
zp->zp_zpl_smallblk = os->os_zpl_special_smallblock;
zp->zp_storage_type = dn ? dn->dn_storage_type : DMU_OT_NONE;
ASSERT3U(zp->zp_compress, !=, ZIO_COMPRESS_INHERIT);

View File

@ -2116,6 +2116,12 @@ spa_preferred_class(spa_t *spa, const zio_t *zio)
boolean_t tried_special = (mc == spa_special_class(spa));
const zio_prop_t *zp = &zio->io_prop;
/* Gang children should always use the class of their parents. */
if (zio->io_flags & ZIO_FLAG_GANG_CHILD) {
ASSERT(mc != NULL);
return (mc);
}
/*
* Override object type for the purposes of selecting a storage class.
* Primarily for DMU_OTN_ types where we can't explicitly control their
@ -2140,39 +2146,23 @@ spa_preferred_class(spa_t *spa, const zio_t *zio)
return (spa_normal_class(spa));
}
/* Indirect blocks for user data can land in special if allowed */
if (zp->zp_level > 0 &&
(DMU_OT_IS_FILE(objtype) || objtype == DMU_OT_ZVOL)) {
if (zfs_user_indirect_is_special && spa_has_special(spa) &&
!tried_special)
return (spa_special_class(spa));
else
return (spa_normal_class(spa));
}
if (!spa_has_special(spa) || tried_special)
return (spa_normal_class(spa));
if (DMU_OT_IS_METADATA(objtype) || zp->zp_level > 0) {
if (spa_has_special(spa) && !tried_special)
return (spa_special_class(spa));
else
return (spa_normal_class(spa));
}
if (DMU_OT_IS_METADATA(objtype) ||
(zfs_user_indirect_is_special && zp->zp_level > 0))
return (spa_special_class(spa));
/*
* Allow small file or zvol blocks in special class if opted in by
* the special_smallblk property. However, always leave a reserve of
* Allow small blocks in special class. However, leave a reserve of
* zfs_special_class_metadata_reserve_pct exclusively for metadata.
*/
if ((DMU_OT_IS_FILE(objtype) || objtype == DMU_OT_ZVOL) &&
spa_has_special(spa) && !tried_special &&
zio->io_size <= zp->zp_zpl_smallblk) {
if (zio->io_size <= zp->zp_zpl_smallblk) {
metaslab_class_t *special = spa_special_class(spa);
uint64_t alloc = metaslab_class_get_alloc(special);
uint64_t space = metaslab_class_get_space(special);
uint64_t limit =
(space * (100 - zfs_special_class_metadata_reserve_pct))
/ 100;
uint64_t limit = metaslab_class_get_space(special) *
(100 - zfs_special_class_metadata_reserve_pct) / 100;
if (alloc < limit)
if (metaslab_class_get_alloc(special) < limit)
return (special);
}