diff --git a/man/man7/zfsprops.7 b/man/man7/zfsprops.7 index 429369bd2e..132f4585cb 100644 --- a/man/man7/zfsprops.7 +++ b/man/man7/zfsprops.7 @@ -1228,12 +1228,12 @@ This feature must be enabled to be used .Pc . .It Sy special_small_blocks Ns = Ns Ar size This value represents the threshold block size for including small file -blocks into the special allocation class. +or zvol blocks into the special allocation class. Blocks smaller than or equal to this value will be assigned to the special allocation class while greater blocks will be assigned to the regular class. Valid values are zero or a power of two from 512 up to 1048576 (1 MiB). -The default size is 0 which means no small file blocks +The default size is 0 which means no small file or zvol blocks will be allocated in the special class. .Pp Before setting this property, a special class vdev must be added to the diff --git a/man/man7/zpoolconcepts.7 b/man/man7/zpoolconcepts.7 index 18dfca6dc8..aa6d5ce1aa 100644 --- a/man/man7/zpoolconcepts.7 +++ b/man/man7/zpoolconcepts.7 @@ -487,7 +487,8 @@ current state of the pool won't be scanned during a scrub. Allocations in the special class are dedicated to specific block types. By default, this includes all metadata, the indirect blocks of user data, and any deduplication tables. -The class can also be provisioned to accept small file blocks. +The class can also be provisioned to accept small file blocks or zvol blocks +on a per dataset granularity. .Pp A pool must always have at least one normal .Pq non- Ns Sy dedup Ns /- Ns Sy special @@ -502,7 +503,7 @@ Deduplication tables can be excluded from the special class by unsetting the .Sy zfs_ddt_data_is_special ZFS module parameter. .Pp -Inclusion of small file blocks in the special class is opt-in. +Inclusion of small file or zvol blocks in the special class is opt-in. Each dataset can control the size of small file blocks allowed in the special class by setting the .Sy special_small_blocks diff --git a/module/zcommon/zfs_prop.c b/module/zcommon/zfs_prop.c index 764993b45e..e1c088fa4a 100644 --- a/module/zcommon/zfs_prop.c +++ b/module/zcommon/zfs_prop.c @@ -701,7 +701,8 @@ zfs_prop_init(void) ZFS_TYPE_FILESYSTEM, "512 to 1M, power of 2", "RECSIZE", B_FALSE, sfeatures); zprop_register_number(ZFS_PROP_SPECIAL_SMALL_BLOCKS, - "special_small_blocks", 0, PROP_INHERIT, ZFS_TYPE_FILESYSTEM, + "special_small_blocks", 0, PROP_INHERIT, + ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "zero or 512 to 1M, power of 2", "SPECIAL_SMALL_BLOCKS", B_FALSE, sfeatures); diff --git a/module/zfs/dmu.c b/module/zfs/dmu.c index 8b440aafba..e3bb9b9087 100644 --- a/module/zfs/dmu.c +++ b/module/zfs/dmu.c @@ -2152,7 +2152,8 @@ 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_zpl_smallblk = (DMU_OT_IS_FILE(zp->zp_type) || + zp->zp_type == DMU_OT_ZVOL) ? os->os_zpl_special_smallblock : 0; ASSERT3U(zp->zp_compress, !=, ZIO_COMPRESS_INHERIT); diff --git a/module/zfs/spa_misc.c b/module/zfs/spa_misc.c index d1d41bbe72..96295a8708 100644 --- a/module/zfs/spa_misc.c +++ b/module/zfs/spa_misc.c @@ -2035,11 +2035,11 @@ spa_preferred_class(spa_t *spa, uint64_t size, dmu_object_type_t objtype, } /* - * Allow small file blocks in special class in some cases (like - * for the dRAID vdev feature). But always leave a reserve of + * Allow small file or zvol blocks in special class if opted in by + * the special_smallblk property. However, always leave a reserve of * zfs_special_class_metadata_reserve_pct exclusively for metadata. */ - if (DMU_OT_IS_FILE(objtype) && + if ((DMU_OT_IS_FILE(objtype) || objtype == DMU_OT_ZVOL) && has_special_class && size <= special_smallblk) { metaslab_class_t *special = spa_special_class(spa); uint64_t alloc = metaslab_class_get_alloc(special); diff --git a/tests/runfiles/common.run b/tests/runfiles/common.run index ac2c541a91..c322492d7f 100644 --- a/tests/runfiles/common.run +++ b/tests/runfiles/common.run @@ -37,7 +37,8 @@ tests = ['alloc_class_001_pos', 'alloc_class_002_neg', 'alloc_class_003_pos', 'alloc_class_004_pos', 'alloc_class_005_pos', 'alloc_class_006_pos', 'alloc_class_007_pos', 'alloc_class_008_pos', 'alloc_class_009_pos', 'alloc_class_010_pos', 'alloc_class_011_neg', 'alloc_class_012_pos', - 'alloc_class_013_pos', 'alloc_class_014_neg', 'alloc_class_015_pos'] + 'alloc_class_013_pos', 'alloc_class_014_neg', 'alloc_class_015_pos', + 'alloc_class_016_pos'] tags = ['functional', 'alloc_class'] [tests/functional/append] diff --git a/tests/zfs-tests/tests/Makefile.am b/tests/zfs-tests/tests/Makefile.am index 00f306122d..6af36ab4fe 100644 --- a/tests/zfs-tests/tests/Makefile.am +++ b/tests/zfs-tests/tests/Makefile.am @@ -421,6 +421,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \ functional/alloc_class/alloc_class_013_pos.ksh \ functional/alloc_class/alloc_class_014_neg.ksh \ functional/alloc_class/alloc_class_015_pos.ksh \ + functional/alloc_class/alloc_class_016_pos.ksh \ functional/alloc_class/cleanup.ksh \ functional/alloc_class/setup.ksh \ functional/append/file_append.ksh \ diff --git a/tests/zfs-tests/tests/functional/alloc_class/alloc_class_016_pos.ksh b/tests/zfs-tests/tests/functional/alloc_class/alloc_class_016_pos.ksh new file mode 100755 index 0000000000..1dfd19449d --- /dev/null +++ b/tests/zfs-tests/tests/functional/alloc_class/alloc_class_016_pos.ksh @@ -0,0 +1,59 @@ +#!/bin/ksh -p + +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +. $STF_SUITE/tests/functional/alloc_class/alloc_class.kshlib + +# +# DESCRIPTION: +# File blocks and zvol blocks, where special_small_blocks is active, +# are expected to end up in the special class. +# + +verify_runnable "global" + +claim="File and zvol blocks using special_small_blocks end up in special class" + +log_assert $claim +log_onexit cleanup +log_must disk_setup + +log_must zpool create $TESTPOOL $ZPOOL_DISKS special $CLASS_DISK0 + +# Provision a filesystem with special_small_blocks and copy 10M to it +log_must zfs create -o compression=off -o special_small_blocks=32K \ + -o recordsize=32K $TESTPOOL/$TESTFS +log_must dd if=/dev/urandom of=/$TESTPOOL/$TESTFS/testfile bs=1M count=10 + +# Provision a volume with special_small_blocks and copy 10M to it +log_must zfs create -V 100M -b 32K -o special_small_blocks=32K \ + -o compression=off $TESTPOOL/$TESTVOL +block_device_wait "$ZVOL_DEVDIR/$TESTPOOL/$TESTVOL" +log_must dd if=/dev/urandom of=$ZVOL_DEVDIR/$TESTPOOL/$TESTVOL bs=1M count=10 + +sync_pool $TESTPOOL +zpool list -v $TESTPOOL + +# Get the amount allocated to special vdev using vdev 'allocated' property +result=$(zpool get -Hp allocated $TESTPOOL $CLASS_DISK0) +set -- $result +allocated=$3 +echo $allocated bytes allocated on special device $CLASS_DISK0 + +# Confirm that at least 20M was allocated +if [[ $allocated -lt 20971520 ]] +then + log_fail "$allocated on special vdev $CLASS_DISK0, but expecting 20M" +fi + +log_must zpool destroy -f "$TESTPOOL" +log_pass $claim