diff --git a/cmd/dbufstat/dbufstat.in b/cmd/dbufstat/dbufstat.in index 1d4eb39d7242..7497b9e402bb 100755 --- a/cmd/dbufstat/dbufstat.in +++ b/cmd/dbufstat/dbufstat.in @@ -358,7 +358,8 @@ def get_compstring(c): "ZIO_COMPRESS_GZIP_6", "ZIO_COMPRESS_GZIP_7", "ZIO_COMPRESS_GZIP_8", "ZIO_COMPRESS_GZIP_9", "ZIO_COMPRESS_ZLE", "ZIO_COMPRESS_LZ4", - "ZIO_COMPRESS_ZSTD", "ZIO_COMPRESS_FUNCTION"] + "ZIO_COMPRESS_ZSTD", "ZIO_COMPRESS_ADAPTIVE", + "ZIO_COMPRESS_FUNCTION"] # If "-rr" option is used, don't convert to string representation if raw > 1: diff --git a/include/sys/Makefile.am b/include/sys/Makefile.am index a944c5ea834d..44403a45554c 100644 --- a/include/sys/Makefile.am +++ b/include/sys/Makefile.am @@ -15,6 +15,7 @@ COMMON_H = \ bptree.h \ btree.h \ bqueue.h \ + compress_adaptive.h \ dataset_kstats.h \ dbuf.h \ ddt.h \ diff --git a/include/sys/compress_adaptive.h b/include/sys/compress_adaptive.h new file mode 100644 index 000000000000..38315006d42d --- /dev/null +++ b/include/sys/compress_adaptive.h @@ -0,0 +1,42 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2019, n1kl (bunge) + */ + +#ifndef _SYS_ADAPTIVE_COMPRESS_H +#define _SYS_ADAPTIVE_COMPRESS_H + +#define COMPRESS_ADAPTIVE_LEVELS 10 + +#include +#include + +size_t compress_adaptive(zio_t *zio, abd_t *src, void *dst, + size_t s_len, enum zio_compress *c, uint8_t level); + +void compress_calc_avg_without_zero(uint64_t act, uint64_t *res, int n); + +uint64_t compress_calc_Bps(uint64_t byte, hrtime_t delay); + + +#endif /* _SYS_ADAPTIVE_COMPRESS_H */ diff --git a/include/sys/dsl_dataset.h b/include/sys/dsl_dataset.h index f5816a934c5f..154cd0683a5c 100644 --- a/include/sys/dsl_dataset.h +++ b/include/sys/dsl_dataset.h @@ -488,6 +488,8 @@ boolean_t dsl_dataset_get_uint64_array_feature(dsl_dataset_t *ds, void dsl_dataset_activate_redaction(dsl_dataset_t *ds, uint64_t *redact_snaps, uint64_t num_redact_snaps, dmu_tx_t *tx); +int dsl_dataset_activate_compress_adaptive(const char *ddname); + #ifdef ZFS_DEBUG #define dprintf_ds(ds, fmt, ...) do { \ if (zfs_flags & ZFS_DEBUG_DPRINTF) { \ diff --git a/include/sys/fs/zfs.h b/include/sys/fs/zfs.h index fe63d735babc..6dcf9ed2d3d5 100644 --- a/include/sys/fs/zfs.h +++ b/include/sys/fs/zfs.h @@ -1130,6 +1130,9 @@ typedef struct vdev_stat_ex { uint64_t vsx_agg_histo[ZIO_PRIORITY_NUM_QUEUEABLE] [VDEV_RQ_HISTO_BUCKETS]; + + uint64_t vsx_diskBps[ZIO_TYPES]; + } vdev_stat_ex_t; /* diff --git a/include/sys/vdev_impl.h b/include/sys/vdev_impl.h index 3c4c3fb5a279..f8fea4c6cf33 100644 --- a/include/sys/vdev_impl.h +++ b/include/sys/vdev_impl.h @@ -132,6 +132,7 @@ struct vdev_cache { typedef struct vdev_queue_class { uint32_t vqc_active; + uint64_t vqc_queued_size; /* * Sorted by offset or timestamp, depending on if the queue is diff --git a/include/sys/zio.h b/include/sys/zio.h index 4959831716b5..0d270fbe2f61 100644 --- a/include/sys/zio.h +++ b/include/sys/zio.h @@ -41,6 +41,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -527,6 +528,12 @@ struct zio { /* Taskq dispatching state */ taskq_ent_t io_tqent; + + /* stored in pio */ + uint8_t io_compress_level; + boolean_t io_compress_adaptive_exploring; + + uint64_t io_compress_adaptive_Bps[COMPRESS_ADAPTIVE_LEVELS]; }; enum blk_verify_flag { diff --git a/include/sys/zio_compress.h b/include/sys/zio_compress.h index 4a22ad2a2742..53df2e641ebd 100644 --- a/include/sys/zio_compress.h +++ b/include/sys/zio_compress.h @@ -54,6 +54,7 @@ enum zio_compress { ZIO_COMPRESS_ZLE, ZIO_COMPRESS_LZ4, ZIO_COMPRESS_ZSTD, + ZIO_COMPRESS_ADAPTIVE, ZIO_COMPRESS_FUNCTIONS }; diff --git a/include/zfeature_common.h b/include/zfeature_common.h index db0138ae8e39..0dfe5bab1f50 100644 --- a/include/zfeature_common.h +++ b/include/zfeature_common.h @@ -76,6 +76,7 @@ typedef enum spa_feature { SPA_FEATURE_LIVELIST, SPA_FEATURE_DEVICE_REBUILD, SPA_FEATURE_ZSTD_COMPRESS, + SPA_FEATURE_COMPRESS_ADAPTIVE, SPA_FEATURES } spa_feature_t; diff --git a/lib/libzpool/Makefile.am b/lib/libzpool/Makefile.am index 992c21cc1560..8ae7672581aa 100644 --- a/lib/libzpool/Makefile.am +++ b/lib/libzpool/Makefile.am @@ -62,6 +62,7 @@ KERNEL_C = \ btree.c \ bqueue.c \ cityhash.c \ + compress_adaptive.c \ dbuf.c \ dbuf_stats.c \ ddt.c \ diff --git a/man/man5/zpool-features.5 b/man/man5/zpool-features.5 index 36c4343a1388..3f7ef0909254 100644 --- a/man/man5/zpool-features.5 +++ b/man/man5/zpool-features.5 @@ -16,6 +16,7 @@ .\" Portions Copyright [yyyy] [name of copyright owner] .\" Copyright (c) 2019, Klara Inc. .\" Copyright (c) 2019, Allan Jude +.\" Copyright (c) 2019, RubenKelevra .TH ZPOOL-FEATURES 5 "Aug 24, 2020" OpenZFS .SH NAME zpool\-features \- ZFS pool feature descriptions @@ -417,7 +418,34 @@ in which new features are enabled. This has no user-visible impact, but other features may depend on this feature. This feature becomes \fBactive\fR as soon as it is enabled and will -never return to being \fBenabled\fB. +never return to being \fBenabled\fR. +.RE + +.sp +.ne 2 +.na +\fB\fBcompress_adaptive\fR\fR +.ad +.RS 4n +.TS +l l . +GUID org.zfsonlinux:compress_adaptive +READ\-ONLY COMPATIBLE yes +DEPENDENCIES lz4_compress,extensible_dataset +.TE + +\fBcompress_adaptive\fR chooses the compression algorithm out of lz4 and gzip[1-9] +to perform with optimal write throughput. + +When the \fBcompress_adaptive\fR feature is set to \fBenabled\fR, the +administrator can turn on \fBcompress_adaptive\fR on any dataset on the +pool using the \fBzfs\fR(8) command. Please note that doing so will +immediately activate the \fBcompress_adaptive\fR feature on the underlying +pool. + +This feature becomes \fBactive\fR as soon as it is used on one dataset and will +return to being \fBenabled\fR once all filesystems that have ever had their compression set to ++\fBcompress_adaptive\fR are destroyed. .RE .sp diff --git a/man/man8/zfsprops.8 b/man/man8/zfsprops.8 index a3392d6c0019..00e6bb12998c 100644 --- a/man/man8/zfsprops.8 +++ b/man/man8/zfsprops.8 @@ -778,7 +778,7 @@ Changing this property affects only newly-written data. .It Xo .Sy compression Ns = Ns Sy on Ns | Ns Sy off Ns | Ns Sy gzip Ns | Ns .Sy gzip- Ns Em N Ns | Ns Sy lz4 Ns | Ns Sy lzjb Ns | Ns Sy zle Ns | Ns Sy zstd Ns | Ns -.Sy zstd- Ns Em N Ns | Ns Sy zstd-fast Ns | Ns Sy zstd-fast- Ns Em N +.Sy zstd- Ns Em N Ns | Ns Sy zstd-fast Ns | Ns Sy zstd-fast- Ns Em N | Ns Sy adaptive Ns .Xc Controls the compression algorithm used for this dataset. .Pp @@ -1989,4 +1989,4 @@ Use the .Nm zfs Cm inherit command to clear a user property. If the property is not defined in any parent dataset, it is removed entirely. -Property values are limited to 8192 bytes. +Property values are limited to 8192 bytes. \ No newline at end of file diff --git a/module/zcommon/zfeature_common.c b/module/zcommon/zfeature_common.c index 97ddacbab9e0..5d7d534f0998 100644 --- a/module/zcommon/zfeature_common.c +++ b/module/zcommon/zfeature_common.c @@ -27,6 +27,7 @@ * Copyright (c) 2017, Intel Corporation. * Copyright (c) 2019, Klara Inc. * Copyright (c) 2019, Allan Jude + * Copyright (c) 2019, n1kl (bunge) */ #ifndef _KERNEL @@ -293,6 +294,19 @@ zpool_feature_init(void) "LZ4 compression algorithm support.", ZFEATURE_FLAG_ACTIVATE_ON_ENABLE, ZFEATURE_TYPE_BOOLEAN, NULL); + { + static const spa_feature_t compress_adaptive_deps[] = { + SPA_FEATURE_LZ4_COMPRESS, + SPA_FEATURE_EXTENSIBLE_DATASET, + SPA_FEATURE_NONE + }; + zfeature_register(SPA_FEATURE_COMPRESS_ADAPTIVE, + "org.zfsonlinux:compress_adaptive", "compress_adaptive", + "adaptive compression algorithm selection support.", + ZFEATURE_FLAG_PER_DATASET | ZFEATURE_FLAG_READONLY_COMPAT, + ZFEATURE_TYPE_BOOLEAN, compress_adaptive_deps); + } + zfeature_register(SPA_FEATURE_MULTI_VDEV_CRASH_DUMP, "com.joyent:multi_vdev_crash_dump", "multi_vdev_crash_dump", "Crash dumps to multiple vdev pools.", diff --git a/module/zcommon/zfs_prop.c b/module/zcommon/zfs_prop.c index f3dbbc15d25e..32090710cd98 100644 --- a/module/zcommon/zfs_prop.c +++ b/module/zcommon/zfs_prop.c @@ -208,6 +208,9 @@ zfs_prop_init(void) ZIO_COMPLEVEL_ZSTD(ZIO_ZSTD_LEVEL_FAST_500) }, { "zstd-fast-1000", ZIO_COMPLEVEL_ZSTD(ZIO_ZSTD_LEVEL_FAST_1000) }, + + { "adaptive", ZIO_COMPRESS_ADAPTIVE }, + { NULL } }; @@ -414,7 +417,7 @@ zfs_prop_init(void) zprop_register_index(ZFS_PROP_COMPRESSION, "compression", ZIO_COMPRESS_DEFAULT, PROP_INHERIT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, - "on | off | lzjb | gzip | gzip-[1-9] | zle | lz4 | " + "on | off | adaptive | lzjb | gzip | gzip-[1-9] | zle | lz4 | " "zstd | zstd-[1-19] | " "zstd-fast-[1-10,20,30,40,50,60,70,80,90,100,500,1000]", "COMPRESS", compress_table); diff --git a/module/zfs/Makefile.in b/module/zfs/Makefile.in index 259ac4dc926c..8d172c7a0a91 100644 --- a/module/zfs/Makefile.in +++ b/module/zfs/Makefile.in @@ -19,6 +19,7 @@ $(MODULE)-objs += arc.o $(MODULE)-objs += blkptr.o $(MODULE)-objs += bplist.o $(MODULE)-objs += bpobj.o +$(MODULE)-objs += compress_adaptive.o $(MODULE)-objs += bptree.o $(MODULE)-objs += btree.o $(MODULE)-objs += bqueue.o diff --git a/module/zfs/compress_adaptive.c b/module/zfs/compress_adaptive.c new file mode 100644 index 000000000000..f37cc61636f2 --- /dev/null +++ b/module/zfs/compress_adaptive.c @@ -0,0 +1,264 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2019, n1kl (bunge) + * Copyright (c) 2020, Sebastian Gottschall + * Copyright (c) 2020, Kjeld Schouten-Lebbing + */ + +/* + * Overview: + * If compression takes long then the disk remains idle. If compression is + * faster than the writing speed of the disk then the CPU remains idle as + * compression and writing to the disk happens in parallel. Auto compression + * tries to keep both as busy as possible. + * + * The disk load is observed through the vdev queue. If the queue is empty a + * fast compression algorithm like lz4 with low compression rates is used and + * if the queue is full then gzip-[1-9] can require more CPU time for higher + * compression rates. + */ + +#include +#include +#include +#include + +/* + * Enum of included compression algorithms levels + * sorted from cpu-light to cpu-heavy + */ +enum zio_compress ac_compress[COMPRESS_ADAPTIVE_LEVELS] = { + ZIO_COMPRESS_LZ4, + ZIO_COMPRESS_GZIP_1, + ZIO_COMPRESS_GZIP_2, + ZIO_COMPRESS_GZIP_3, + ZIO_COMPRESS_GZIP_4, + ZIO_COMPRESS_GZIP_5, + ZIO_COMPRESS_GZIP_6, + ZIO_COMPRESS_GZIP_7, + ZIO_COMPRESS_GZIP_8, + ZIO_COMPRESS_GZIP_9}; + + +static void +compress_set_algorithm(uint64_t level, enum zio_compress *c) +{ + *c = ac_compress[level]; +} + +static void +compress_set_default_algorithm(enum zio_compress *c) +{ + compress_set_algorithm(0, c); +} + +static uint64_t +compress_calc_delay(uint64_t byte, uint64_t byte_per_second) +{ + return ((byte * 1000000000) / byte_per_second); +} + +uint64_t +compress_calc_Bps(uint64_t byte, hrtime_t delay) +{ + return ((byte * 1000000000) / delay); +} + +void +compress_calc_avg_without_zero(uint64_t act, uint64_t *res, int n) +{ + uint64_t prev = *res; + if (act) { + if (prev) { + *res = (act + prev * (n - 1)) / n; + } else { + *res = act; + } + } +} + +static uint64_t +compress_vdev_queue_delay(uint64_t size, vdev_t *vd) +{ + uint64_t vd_writeBps = vd->vdev_stat_ex.vsx_diskBps[ZIO_TYPE_WRITE]; + + if (vd_writeBps == 0) { + return (0); + } + + uint64_t vd_queued_size_write = + vd->vdev_queue.vq_class[ZIO_PRIORITY_ASYNC_WRITE].vqc_queued_size; + + uint32_t max_queue_depth = zfs_vdev_async_write_max_active * + zfs_vdev_queue_depth_pct / 50; + /* + * keep at least 10 ZIOs in queue * compression factor about 2 + * = average 25 + */ + uint64_t queue_offset = size * (max_queue_depth / 4); + if (vd_queued_size_write >= queue_offset) { + vd_queued_size_write -= queue_offset; + } else { + vd_queued_size_write = 0; + } + + return (compress_calc_delay(vd_queued_size_write, vd_writeBps)); +} + +static uint64_t +compress_min_queue_delay(uint64_t size, vdev_t *vd) +{ + uint64_t min_delay = 0; + + if (!vd->vdev_children) { // is leaf + min_delay = compress_vdev_queue_delay(size, vd); + } else { + int i; + for (i = 0; i < vd->vdev_children; i++) { + uint64_t vdev_delay = compress_min_queue_delay(size, + vd->vdev_child[i]); + if (vdev_delay) { + if (min_delay == 0) { + min_delay = vdev_delay; + } else if (vdev_delay < min_delay) { + min_delay = vdev_delay; + } + } + } + } + return (min_delay); +} + +static void +compress_update_pio(uint64_t compressBps, uint8_t compress_level, + zio_t *pio) +{ + int n = 10; + compress_calc_avg_without_zero(compressBps, + &pio->io_compress_adaptive_Bps[compress_level], n); + + if (pio->io_compress_adaptive_exploring) { + pio->io_compress_adaptive_exploring = B_FALSE; + } else { + pio->io_compress_level = compress_level; + } +} + +static uint64_t +compress_get_faster_level(uint64_t lsize, uint8_t level, + uint64_t available_queue_delay, zio_t *pio) +{ + if (level < COMPRESS_ADAPTIVE_LEVELS - 1) { + uint64_t fasterBps = pio->io_compress_adaptive_Bps[level + 1]; + + if (fasterBps != 0) { + + uint64_t new_required_queue_delay = + compress_calc_delay(lsize, fasterBps); + + if (new_required_queue_delay < available_queue_delay) { + level++; + } + + } else if (pio->io_compress_adaptive_exploring == B_FALSE) { + pio->io_compress_adaptive_exploring = B_TRUE; + level++; + } + } + return (level); +} + +static uint64_t +compress_get_slower_level(uint64_t lsize, uint8_t level, + uint64_t required_queue_delay, uint64_t available_queue_delay, zio_t *pio) +{ + while (required_queue_delay > available_queue_delay) { + if (level > 0) { + level--; + required_queue_delay = compress_calc_delay(lsize, + pio->io_compress_adaptive_Bps[level]); + } else { + break; + } + } + return (level); +} + +static uint64_t +compress_get_optimal_level(uint64_t lsize, vdev_t *rvd, zio_t *pio) +{ + uint64_t available_queue_delay; + uint64_t required_queue_delay; + uint64_t level = pio->io_compress_level; + + if (pio->io_compress_adaptive_Bps[level] == 0) { + return (level); + } + + available_queue_delay = compress_min_queue_delay(lsize, rvd); + required_queue_delay = compress_calc_delay(lsize, + pio->io_compress_adaptive_Bps[level]); + + + if (required_queue_delay < available_queue_delay) { + level = compress_get_faster_level(lsize, level, + available_queue_delay, pio); + } else { + level = compress_get_slower_level(lsize, level, + required_queue_delay, available_queue_delay, pio); + } + return (level); + +} + +size_t +compress_adaptive(zio_t *zio, abd_t *src, void *dst, size_t s_len, + enum zio_compress *c, uint8_t c_level) +{ + size_t psize; + vdev_t *rvd = zio->io_spa->spa_root_vdev; + zio_t *pio = zio_unique_parent(zio); + + compress_set_default_algorithm(c); + + if (pio == NULL) { + psize = zio_compress_data(*c, src, dst, s_len, c_level); + } else { + hrtime_t compress_begin = gethrtime(); + + uint64_t level = compress_get_optimal_level(zio->io_lsize, + rvd, pio); + compress_set_algorithm(level, c); + + /* todo, this level here will not work for zstd */ + psize = zio_compress_data(*c, src, dst, s_len, level); + + hrtime_t compress_delay = gethrtime() - compress_begin; + uint64_t compressBps = compress_calc_Bps(zio->io_lsize, + compress_delay); + + compress_update_pio(compressBps, level, pio); + } + + return (psize); +} diff --git a/module/zfs/dsl_dataset.c b/module/zfs/dsl_dataset.c index 1fcd83db7988..f1fa8eb33629 100644 --- a/module/zfs/dsl_dataset.c +++ b/module/zfs/dsl_dataset.c @@ -30,6 +30,7 @@ * Copyright 2017 Nexenta Systems, Inc. * Copyright (c) 2019, Klara Inc. * Copyright (c) 2019, Allan Jude + * Copyright (c) 2019, n1kl (bunge) * Copyright (c) 2020 The FreeBSD Foundation [1] * * [1] Portions of this software were developed by Allan Jude @@ -4975,6 +4976,58 @@ dsl_dataset_activate_redaction(dsl_dataset_t *ds, uint64_t *redact_snaps, ds->ds_feature[SPA_FEATURE_REDACTED_DATASETS] = ftuaa; } +static int +dsl_dataset_actv_compress_adaptive_check(void *arg, dmu_tx_t *tx) +{ + char *ddname = (char *)arg; + dsl_pool_t *dp = dmu_tx_pool(tx); + dsl_dataset_t *ds; + int error; + + error = dsl_dataset_hold(dp, ddname, FTAG, &ds); + if (error != 0) + return (error); + + if (!spa_feature_is_enabled(dp->dp_spa, + SPA_FEATURE_COMPRESS_ADAPTIVE)) { + dsl_dataset_rele(ds, FTAG); + return (SET_ERROR(ENOTSUP)); + } + + dsl_dataset_rele(ds, FTAG); + return (0); +} + +static void +dsl_dataset_actv_compress_adaptive_sync(void *arg, dmu_tx_t *tx) +{ + char *ddname = (char *)arg; + dsl_pool_t *dp = dmu_tx_pool(tx); + dsl_dataset_t *ds; + + VERIFY0(dsl_dataset_hold(dp, ddname, FTAG, &ds)); + + if (!dsl_dataset_feature_is_active(ds, SPA_FEATURE_COMPRESS_ADAPTIVE)) { + dsl_dataset_activate_feature(ds->ds_object, + SPA_FEATURE_COMPRESS_ADAPTIVE, (void *)B_TRUE, tx); + ds->ds_feature[SPA_FEATURE_COMPRESS_ADAPTIVE] = (void *)B_TRUE; + } + dsl_dataset_rele(ds, FTAG); +} + + +int +dsl_dataset_activate_compress_adaptive(const char *ddname) +{ + int error; + + error = dsl_sync_task(ddname, dsl_dataset_actv_compress_adaptive_check, + dsl_dataset_actv_compress_adaptive_sync, (void *)ddname, 0, + ZFS_SPACE_CHECK_RESERVED); + + return (error); +} + /* BEGIN CSTYLED */ #if defined(_LP64) #define RECORDSIZE_PERM ZMOD_RW diff --git a/module/zfs/vdev.c b/module/zfs/vdev.c index a94101485c94..d06b3d873452 100644 --- a/module/zfs/vdev.c +++ b/module/zfs/vdev.c @@ -28,6 +28,8 @@ * Copyright 2017 Joyent, Inc. * Copyright (c) 2017, Intel Corporation. * Copyright (c) 2019, Datto Inc. All rights reserved. + * Copyright (c) 2019, n1kl (bunge) + * Copyright (c) 2019, RubenKelevra */ #include @@ -56,6 +58,7 @@ #include #include #include +#include /* default target for number of metaslabs per top-level vdev */ int zfs_vdev_default_ms_count = 200; @@ -4331,6 +4334,14 @@ vdev_stat_update(zio_t *zio, uint64_t psize) } if (zio->io_delta && zio->io_delay) { + int n = 1000; // average over 1000 zios + + uint64_t bps = compress_calc_Bps( + psize, zio->io_delay); + + compress_calc_avg_without_zero( + bps, &vsx->vsx_diskBps[type], n); + vsx->vsx_queue_histo[priority] [L_HISTO(zio->io_delta - zio->io_delay)]++; vsx->vsx_disk_histo[type] diff --git a/module/zfs/vdev_queue.c b/module/zfs/vdev_queue.c index a8ef3d7474c9..2ff9efbebe1e 100644 --- a/module/zfs/vdev_queue.c +++ b/module/zfs/vdev_queue.c @@ -25,6 +25,7 @@ /* * Copyright (c) 2012, 2018 by Delphix. All rights reserved. + * Copyright (c) 2019, n1kl (bunge) */ #include @@ -468,6 +469,7 @@ vdev_queue_io_add(vdev_queue_t *vq, zio_t *zio) ASSERT3U(zio->io_priority, <, ZIO_PRIORITY_NUM_QUEUEABLE); avl_add(vdev_queue_class_tree(vq, zio->io_priority), zio); avl_add(vdev_queue_type_tree(vq, zio->io_type), zio); + vq->vq_class[zio->io_priority].vqc_queued_size += zio->io_size; if (shk->kstat != NULL) { mutex_enter(&shk->lock); @@ -485,6 +487,7 @@ vdev_queue_io_remove(vdev_queue_t *vq, zio_t *zio) ASSERT3U(zio->io_priority, <, ZIO_PRIORITY_NUM_QUEUEABLE); avl_remove(vdev_queue_class_tree(vq, zio->io_priority), zio); avl_remove(vdev_queue_type_tree(vq, zio->io_type), zio); + vq->vq_class[zio->io_priority].vqc_queued_size -= zio->io_size; if (shk->kstat != NULL) { mutex_enter(&shk->lock); diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index 94cd1a3dc834..ba39e361bd2d 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -2467,6 +2467,11 @@ zfs_prop_set_special(const char *dsname, zprop_source_t source, break; case ZFS_PROP_COMPRESSION: err = dsl_dataset_set_compression(dsname, source, intval); + + if (intval == ZIO_COMPRESS_ADAPTIVE) { + err = dsl_dataset_activate_compress_adaptive(dsname); + } + /* * Set err to -1 to force the zfs_set_prop_nvlist code down the * default path to set the value in the nvlist. @@ -4486,6 +4491,20 @@ zfs_check_settable(const char *dsname, nvpair_t *pair, cred_t *cr) } spa_close(spa, FTAG); } + + if (intval == ZIO_COMPRESS_ADAPTIVE) { + spa_t *spa; + + if ((err = spa_open(dsname, &spa, FTAG)) != 0) + return (err); + + if (!spa_feature_is_enabled(spa, + SPA_FEATURE_COMPRESS_ADAPTIVE)) { + spa_close(spa, FTAG); + return (SET_ERROR(ENOTSUP)); + } + spa_close(spa, FTAG); + } } break; diff --git a/module/zfs/zio.c b/module/zfs/zio.c index 8a8fbccd7d63..8d2293c33a60 100644 --- a/module/zfs/zio.c +++ b/module/zfs/zio.c @@ -25,6 +25,8 @@ * Copyright (c) 2017, Intel Corporation. * Copyright (c) 2019, Klara Inc. * Copyright (c) 2019, Allan Jude + * Copyright (c) 2019, n1kl (bunge) + * Copyright (c) 2020, Sebastian Gottschall */ #include @@ -50,7 +52,7 @@ #include #include #include - +#include /* * ========================================================================== * I/O type descriptions @@ -1682,8 +1684,13 @@ zio_write_compress(zio_t *zio) if (compress != ZIO_COMPRESS_OFF && !(zio->io_flags & ZIO_FLAG_RAW_COMPRESS)) { void *cbuf = zio_buf_alloc(lsize); - psize = zio_compress_data(compress, zio->io_abd, cbuf, lsize, - zp->zp_complevel); + if (compress == ZIO_COMPRESS_ADAPTIVE) { + psize = compress_adaptive(zio, zio->io_abd, + cbuf, lsize, &compress, zp->zp_complevel); + } else { + psize = zio_compress_data(compress, zio->io_abd, + cbuf, lsize, zp->zp_complevel); + } if (psize == 0 || psize >= lsize) { compress = ZIO_COMPRESS_OFF; zio_buf_free(cbuf, lsize); diff --git a/module/zfs/zio_compress.c b/module/zfs/zio_compress.c index 2db3cec35d5d..01bb6f8d1407 100644 --- a/module/zfs/zio_compress.c +++ b/module/zfs/zio_compress.c @@ -68,6 +68,7 @@ zio_compress_info_t zio_compress_table[ZIO_COMPRESS_FUNCTIONS] = { {"lz4", 0, lz4_compress_zfs, lz4_decompress_zfs, NULL}, {"zstd", ZIO_ZSTD_LEVEL_DEFAULT, zfs_zstd_compress, zfs_zstd_decompress, zfs_zstd_decompress_level}, + {"adaptive", 0, NULL, NULL, NULL}, }; uint8_t diff --git a/tests/zfs-tests/include/properties.shlib b/tests/zfs-tests/include/properties.shlib index 6d467b60051d..0b3586ea8f25 100644 --- a/tests/zfs-tests/include/properties.shlib +++ b/tests/zfs-tests/include/properties.shlib @@ -15,7 +15,7 @@ . $STF_SUITE/include/libtest.shlib -typeset -a compress_prop_vals=('off' 'lzjb' 'lz4' 'gzip' 'zle' 'zstd') +typeset -a compress_prop_vals=('off' 'lzjb' 'lz4' 'gzip' 'zle' 'zstd' 'adaptive') typeset -a checksum_prop_vals=('on' 'off' 'fletcher2' 'fletcher4' 'sha256' 'noparity' 'sha512' 'skein') if ! is_freebsd; then diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get.cfg b/tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get.cfg index 8abef65de19f..e63fc47bd05b 100644 --- a/tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get.cfg +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get.cfg @@ -80,6 +80,7 @@ typeset -a properties=( "feature@bookmark_written" "feature@log_spacemap" "feature@device_rebuild" + "feature@compress_adaptive" ) if is_linux || is_freebsd; then diff --git a/tests/zfs-tests/tests/functional/history/history_002_pos.ksh b/tests/zfs-tests/tests/functional/history/history_002_pos.ksh index b077603e828f..8926019ccef4 100755 --- a/tests/zfs-tests/tests/functional/history/history_002_pos.ksh +++ b/tests/zfs-tests/tests/functional/history/history_002_pos.ksh @@ -88,7 +88,7 @@ props=( compression gzip compression gzip-$((RANDOM%9 + 1)) compression zstd compression zstd-$((RANDOM%9 + 1)) compression zstd-fast copies $((RANDOM%3 + 1)) - compression zstd-fast-$((RANDOM%9 + 1)) + compression adaptive compression zstd-fast-$((RANDOM%9 + 1)) ) elif is_freebsd; then # property value property value