diff options
author | loli10K <[email protected]> | 2019-02-08 21:32:12 +0100 |
---|---|---|
committer | Matthew Ahrens <[email protected]> | 2019-02-08 12:32:12 -0800 |
commit | 4417096956f7439322c65d9e70a4526df45ea8d0 (patch) | |
tree | 178e2f569132f796e7e724711be9a681671608c0 | |
parent | 0902c4577f4ba2a3687549f7d5d19718a275fb52 (diff) |
Pool allocation classes misplacing small file blocks
Due to an off-by-one condition in spa_preferred_class() we are picking
the "normal" allocation class instead of the "special" one for file
blocks with size equal to the special_small_blocks property value.
This change fix the small code issue, update the ZFS Test Suite and the
zfs(8) man page.
Reviewed-by: Brian Behlendorf <[email protected]>
Reviewed-by: Don Brady <[email protected]>
Signed-off-by: loli10K <[email protected]>
Closes #8351
Closes #8361
-rw-r--r-- | man/man8/zfs.8 | 8 | ||||
-rw-r--r-- | module/zfs/spa_misc.c | 2 | ||||
-rwxr-xr-x | tests/zfs-tests/tests/functional/alloc_class/alloc_class_012_pos.ksh | 41 |
3 files changed, 47 insertions, 4 deletions
diff --git a/man/man8/zfs.8 b/man/man8/zfs.8 index be28f2b62..4658c5b8b 100644 --- a/man/man8/zfs.8 +++ b/man/man8/zfs.8 @@ -1521,9 +1521,11 @@ This feature must be enabled to be used .Pc . .It Sy special_small_blocks Ns = Ns Em size This value represents the threshold block size for including small file -blocks into the special allocation class. Valid values are zero or a -power of two from 512B up to 128K. The default size is 0 which means no -small file blocks will be allocated in the special class. +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 512B up to 128K. The default size is 0 which means no small file blocks +will be allocated in the special class. .Pp Before setting this property, a special class vdev must be added to the pool. See diff --git a/module/zfs/spa_misc.c b/module/zfs/spa_misc.c index 877f312b1..0976cc49c 100644 --- a/module/zfs/spa_misc.c +++ b/module/zfs/spa_misc.c @@ -1851,7 +1851,7 @@ spa_preferred_class(spa_t *spa, uint64_t size, dmu_object_type_t objtype, * zfs_special_class_metadata_reserve_pct exclusively for metadata. */ if (DMU_OT_IS_FILE(objtype) && - has_special_class && size < special_smallblk) { + has_special_class && size <= special_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); diff --git a/tests/zfs-tests/tests/functional/alloc_class/alloc_class_012_pos.ksh b/tests/zfs-tests/tests/functional/alloc_class/alloc_class_012_pos.ksh index 2371c5a26..bd6c6631f 100755 --- a/tests/zfs-tests/tests/functional/alloc_class/alloc_class_012_pos.ksh +++ b/tests/zfs-tests/tests/functional/alloc_class/alloc_class_012_pos.ksh @@ -24,6 +24,39 @@ verify_runnable "global" +# +# Verify the file identified by the input <inode> is written on a special vdev +# According to the pool layout used in this test vdev_id 3 and 4 are special +# XXX: move this function to libtest.shlib once we get "Vdev Properties" +# +function file_in_special_vdev # <dataset> <inode> +{ + typeset dataset="$1" + typeset inum="$2" + + zdb -dddddd $dataset $inum | awk '{ +# find DVAs from string "offset level dva" only for L0 (data) blocks +if (match($0,"L0 [0-9]+")) { + dvas[0]=$3 + dvas[1]=$4 + dvas[2]=$5 + for (i = 0; i < 3; ++i) { + if (match(dvas[i],"([^:]+):.*")) { + dva = substr(dvas[i], RSTART, RLENGTH); + # parse DVA from string "vdev:offset:asize" + if (split(dva,arr,":") != 3) { + print "Error parsing DVA: <" dva ">"; + exit 1; + } + # verify vdev is "special" + if (arr[1] < 3) { + exit 1; + } + } + } +}}' +} + claim="Removing a special device from a pool succeeds." log_assert $claim @@ -53,6 +86,13 @@ done log_must sync_pool $TESTPOOL log_must zpool list -v $TESTPOOL +# Verify the files were written in the special class vdevs +for i in 1 2 3 4; do + dataset="$TESTPOOL/$TESTFS" + inum="$(stat -c '%i' /$TESTPOOL/$TESTFS/testfile.$i)" + log_must file_in_special_vdev $dataset $inum +done + # # remove a special allocation vdev and force a remapping # N.B. The 'zfs remap' command has been disabled and may be removed. @@ -67,6 +107,7 @@ log_must sync_pool $TESTPOOL sleep 1 log_must zdb -bbcc $TESTPOOL +log_must zpool list -v $TESTPOOL log_must zpool destroy -f "$TESTPOOL" log_pass $claim |