From 991fc56faec594c3ce25bb6c1347405f4a9eee4f Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Wed, 25 Feb 2026 09:41:38 -0500 Subject: [PATCH] Introduce dedupused/dedupsaved pool properties Currently there is only a dedup ratio reported via pool properties. If dedup is enabled only for some datasets, it is impossible to say how much space the ratio actually covers. Fix this by introducing dedupused/dedupsaved pool properties, similar to earlier added block cloning ones. Combined with work to expose allocation classes stats, it should give user-space enough visibility to correlate `zpool list` and `zfs list` space numbers. Reviewed-by: Tony Hutter Reviewed-by: Ryan Moeller Signed-off-by: Alexander Motin Closes #18245 --- include/sys/ddt.h | 2 ++ include/sys/fs/zfs.h | 2 ++ lib/libzfs/libzfs.abi | 4 +++- lib/libzfs/libzfs_pool.c | 2 ++ man/man7/zpoolprops.7 | 15 +++++++++++++++ module/zcommon/zpool_prop.c | 6 ++++++ module/zfs/ddt_stats.c | 15 +++++++++++++++ module/zfs/spa.c | 4 ++++ .../functional/cli_root/zpool_get/zpool_get.cfg | 2 ++ .../cli_root/zpool_get/zpool_get_parsable.cfg | 4 ++-- 10 files changed, 53 insertions(+), 3 deletions(-) diff --git a/include/sys/ddt.h b/include/sys/ddt.h index 5285614ac..d326ee798 100644 --- a/include/sys/ddt.h +++ b/include/sys/ddt.h @@ -396,6 +396,8 @@ extern void ddt_get_dedup_histogram(spa_t *spa, ddt_histogram_t *ddh); extern void ddt_get_dedup_stats(spa_t *spa, ddt_stat_t *dds_total); extern uint64_t ddt_get_dedup_dspace(spa_t *spa); +extern uint64_t ddt_get_dedup_used(spa_t *spa); +extern uint64_t ddt_get_dedup_saved(spa_t *spa); extern uint64_t ddt_get_pool_dedup_ratio(spa_t *spa); extern int ddt_get_pool_dedup_cached(spa_t *spa, uint64_t *psize); diff --git a/include/sys/fs/zfs.h b/include/sys/fs/zfs.h index ab9b4e746..de2149641 100644 --- a/include/sys/fs/zfs.h +++ b/include/sys/fs/zfs.h @@ -273,6 +273,8 @@ typedef enum { ZPOOL_PROP_DEDUP_TABLE_QUOTA, ZPOOL_PROP_DEDUPCACHED, ZPOOL_PROP_LAST_SCRUBBED_TXG, + ZPOOL_PROP_DEDUPUSED, + ZPOOL_PROP_DEDUPSAVED, ZPOOL_NUM_PROPS } zpool_prop_t; diff --git a/lib/libzfs/libzfs.abi b/lib/libzfs/libzfs.abi index b51984f40..876433c0b 100644 --- a/lib/libzfs/libzfs.abi +++ b/lib/libzfs/libzfs.abi @@ -3370,7 +3370,9 @@ - + + + diff --git a/lib/libzfs/libzfs_pool.c b/lib/libzfs/libzfs_pool.c index 0bfc9ff74..e12308b01 100644 --- a/lib/libzfs/libzfs_pool.c +++ b/lib/libzfs/libzfs_pool.c @@ -380,6 +380,8 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, case ZPOOL_PROP_BCLONESAVED: case ZPOOL_PROP_BCLONEUSED: case ZPOOL_PROP_DEDUP_TABLE_SIZE: + case ZPOOL_PROP_DEDUPUSED: + case ZPOOL_PROP_DEDUPSAVED: case ZPOOL_PROP_DEDUPCACHED: if (literal) (void) snprintf(buf, len, "%llu", diff --git a/man/man7/zpoolprops.7 b/man/man7/zpoolprops.7 index d3b4c2376..3836ec764 100644 --- a/man/man7/zpoolprops.7 +++ b/man/man7/zpoolprops.7 @@ -80,6 +80,21 @@ See .Xr zpool-prefetch 8 . .It Sy dedup_table_size Total on-disk size of the deduplication table. +.It Sy dedupratio +The ratio of the total amount of storage that would be required to store all +the deduplicated blocks without deduplication to the actual storage used. +The +.Sy dedupratio +property is calculated as: +.Pp +.Sy ( ( dedupsaved + dedupused ) * 100 ) / dedupused +.It Sy dedupsaved +The amount of additional storage that would be required if deduplication +was not used. +This represents the space saved by deduplication. +.It Sy dedupused +The amount of storage used by deduplicated blocks. +This is the actual physical space occupied on disk after deduplication. .It Sy expandsize Amount of uninitialized space within the pool or device that can be used to increase the total capacity of the pool. diff --git a/module/zcommon/zpool_prop.c b/module/zcommon/zpool_prop.c index 1be5f9d30..2c6515e93 100644 --- a/module/zcommon/zpool_prop.c +++ b/module/zcommon/zpool_prop.c @@ -117,6 +117,12 @@ zpool_prop_init(void) zprop_register_number(ZPOOL_PROP_DEDUPRATIO, "dedupratio", 0, PROP_READONLY, ZFS_TYPE_POOL, "<1.00x or higher if deduped>", "DEDUP", B_FALSE, sfeatures); + zprop_register_number(ZPOOL_PROP_DEDUPUSED, "dedupused", 0, + PROP_READONLY, ZFS_TYPE_POOL, "", + "DEDUP_USED", B_FALSE, sfeatures); + zprop_register_number(ZPOOL_PROP_DEDUPSAVED, "dedupsaved", 0, + PROP_READONLY, ZFS_TYPE_POOL, "", + "DEDUP_SAVED", B_FALSE, sfeatures); zprop_register_number(ZPOOL_PROP_BCLONEUSED, "bcloneused", 0, PROP_READONLY, ZFS_TYPE_POOL, "", "BCLONE_USED", B_FALSE, sfeatures); diff --git a/module/zfs/ddt_stats.c b/module/zfs/ddt_stats.c index 2c4725dc9..77b8e814d 100644 --- a/module/zfs/ddt_stats.c +++ b/module/zfs/ddt_stats.c @@ -297,6 +297,21 @@ ddt_get_dedup_dspace(spa_t *spa) return (spa->spa_dedup_dspace); } +uint64_t +ddt_get_dedup_used(spa_t *spa) +{ + ddt_stat_t dds_total = { 0 }; + + ddt_get_dedup_stats(spa, &dds_total); + return (dds_total.dds_dsize); +} + +uint64_t +ddt_get_dedup_saved(spa_t *spa) +{ + return (ddt_get_dedup_dspace(spa)); +} + uint64_t ddt_get_pool_dedup_ratio(spa_t *spa) { diff --git a/module/zfs/spa.c b/module/zfs/spa.c index a90509974..386394e09 100644 --- a/module/zfs/spa.c +++ b/module/zfs/spa.c @@ -483,6 +483,10 @@ spa_prop_get_config(spa_t *spa, nvlist_t *nv) spa_prop_add_list(nv, ZPOOL_PROP_DEDUPRATIO, NULL, ddt_get_pool_dedup_ratio(spa), src); + spa_prop_add_list(nv, ZPOOL_PROP_DEDUPUSED, NULL, + ddt_get_dedup_used(spa), src); + spa_prop_add_list(nv, ZPOOL_PROP_DEDUPSAVED, NULL, + ddt_get_dedup_saved(spa), src); spa_prop_add_list(nv, ZPOOL_PROP_BCLONEUSED, NULL, brt_get_used(spa), src); spa_prop_add_list(nv, ZPOOL_PROP_BCLONESAVED, NULL, 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 bdf5fdf85..99a4556f7 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 @@ -65,6 +65,8 @@ typeset -a properties=( "bclonesaved" "bcloneratio" "last_scrubbed_txg" + "dedupused" + "dedupsaved" "feature@async_destroy" "feature@empty_bpobj" "feature@lz4_compress" diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get_parsable.cfg b/tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get_parsable.cfg index f7cd3cfec..2d45ba344 100644 --- a/tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get_parsable.cfg +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get_parsable.cfg @@ -30,5 +30,5 @@ # # Set the expected properties of zpool -typeset -a properties=("allocated" "capacity" "expandsize" "free" "freeing" - "leaked" "size") +typeset -a properties=("allocated" "bcloneused" "bclonesaved" "capacity" + "dedupused" "dedupsaved" "expandsize" "free" "freeing" "leaked" "size")