14fefe1b7SMartin Matuska /* 24fefe1b7SMartin Matuska * CDDL HEADER START 34fefe1b7SMartin Matuska * 44fefe1b7SMartin Matuska * The contents of this file are subject to the terms of the 54fefe1b7SMartin Matuska * Common Development and Distribution License (the "License"). 64fefe1b7SMartin Matuska * You may not use this file except in compliance with the License. 74fefe1b7SMartin Matuska * 84fefe1b7SMartin Matuska * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 94fefe1b7SMartin Matuska * or https://opensource.org/licenses/CDDL-1.0. 104fefe1b7SMartin Matuska * See the License for the specific language governing permissions 114fefe1b7SMartin Matuska * and limitations under the License. 124fefe1b7SMartin Matuska * 134fefe1b7SMartin Matuska * When distributing Covered Code, include this CDDL HEADER in each 144fefe1b7SMartin Matuska * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 154fefe1b7SMartin Matuska * If applicable, add the following below this CDDL HEADER, with the 164fefe1b7SMartin Matuska * fields enclosed by brackets "[]" replaced with your own identifying 174fefe1b7SMartin Matuska * information: Portions Copyright [yyyy] [name of copyright owner] 184fefe1b7SMartin Matuska * 194fefe1b7SMartin Matuska * CDDL HEADER END 204fefe1b7SMartin Matuska */ 214fefe1b7SMartin Matuska 224fefe1b7SMartin Matuska /* 234fefe1b7SMartin Matuska * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 244fefe1b7SMartin Matuska * Copyright (c) 2012, 2016 by Delphix. All rights reserved. 254fefe1b7SMartin Matuska * Copyright (c) 2022 by Pawel Jakub Dawidek 264fefe1b7SMartin Matuska * Copyright (c) 2023, Klara Inc. 274fefe1b7SMartin Matuska */ 284fefe1b7SMartin Matuska 294fefe1b7SMartin Matuska #include <sys/zfs_context.h> 304fefe1b7SMartin Matuska #include <sys/spa.h> 314fefe1b7SMartin Matuska #include <sys/spa_impl.h> 324fefe1b7SMartin Matuska #include <sys/ddt.h> 334fefe1b7SMartin Matuska #include <sys/ddt_impl.h> 344fefe1b7SMartin Matuska 354fefe1b7SMartin Matuska static void 36*e2df9bb4SMartin Matuska ddt_stat_generate(ddt_t *ddt, const ddt_lightweight_entry_t *ddlwe, 37*e2df9bb4SMartin Matuska ddt_stat_t *dds) 384fefe1b7SMartin Matuska { 394fefe1b7SMartin Matuska spa_t *spa = ddt->ddt_spa; 40*e2df9bb4SMartin Matuska uint64_t lsize = DDK_GET_LSIZE(&ddlwe->ddlwe_key); 41*e2df9bb4SMartin Matuska uint64_t psize = DDK_GET_PSIZE(&ddlwe->ddlwe_key); 424fefe1b7SMartin Matuska 434fefe1b7SMartin Matuska memset(dds, 0, sizeof (*dds)); 444fefe1b7SMartin Matuska 45*e2df9bb4SMartin Matuska for (int p = 0; p < DDT_NPHYS(ddt); p++) { 46*e2df9bb4SMartin Matuska const ddt_univ_phys_t *ddp = &ddlwe->ddlwe_phys; 47*e2df9bb4SMartin Matuska ddt_phys_variant_t v = DDT_PHYS_VARIANT(ddt, p); 484fefe1b7SMartin Matuska 49*e2df9bb4SMartin Matuska if (ddt_phys_birth(ddp, v) == 0) 504fefe1b7SMartin Matuska continue; 514fefe1b7SMartin Matuska 52*e2df9bb4SMartin Matuska int ndvas = ddt_phys_dva_count(ddp, v, 53*e2df9bb4SMartin Matuska DDK_GET_CRYPT(&ddlwe->ddlwe_key)); 54*e2df9bb4SMartin Matuska const dva_t *dvas = (ddt->ddt_flags & DDT_FLAG_FLAT) ? 55*e2df9bb4SMartin Matuska ddp->ddp_flat.ddp_dva : ddp->ddp_trad[p].ddp_dva; 56*e2df9bb4SMartin Matuska 57*e2df9bb4SMartin Matuska uint64_t dsize = 0; 584fefe1b7SMartin Matuska for (int d = 0; d < ndvas; d++) 59*e2df9bb4SMartin Matuska dsize += dva_get_dsize_sync(spa, &dvas[d]); 60*e2df9bb4SMartin Matuska 61*e2df9bb4SMartin Matuska uint64_t refcnt = ddt_phys_refcnt(ddp, v); 624fefe1b7SMartin Matuska 634fefe1b7SMartin Matuska dds->dds_blocks += 1; 644fefe1b7SMartin Matuska dds->dds_lsize += lsize; 654fefe1b7SMartin Matuska dds->dds_psize += psize; 664fefe1b7SMartin Matuska dds->dds_dsize += dsize; 674fefe1b7SMartin Matuska 684fefe1b7SMartin Matuska dds->dds_ref_blocks += refcnt; 694fefe1b7SMartin Matuska dds->dds_ref_lsize += lsize * refcnt; 704fefe1b7SMartin Matuska dds->dds_ref_psize += psize * refcnt; 714fefe1b7SMartin Matuska dds->dds_ref_dsize += dsize * refcnt; 724fefe1b7SMartin Matuska } 734fefe1b7SMartin Matuska } 744fefe1b7SMartin Matuska 75*e2df9bb4SMartin Matuska static void 76*e2df9bb4SMartin Matuska ddt_stat_add(ddt_stat_t *dst, const ddt_stat_t *src) 774fefe1b7SMartin Matuska { 78*e2df9bb4SMartin Matuska dst->dds_blocks += src->dds_blocks; 79*e2df9bb4SMartin Matuska dst->dds_lsize += src->dds_lsize; 80*e2df9bb4SMartin Matuska dst->dds_psize += src->dds_psize; 81*e2df9bb4SMartin Matuska dst->dds_dsize += src->dds_dsize; 82*e2df9bb4SMartin Matuska dst->dds_ref_blocks += src->dds_ref_blocks; 83*e2df9bb4SMartin Matuska dst->dds_ref_lsize += src->dds_ref_lsize; 84*e2df9bb4SMartin Matuska dst->dds_ref_psize += src->dds_ref_psize; 85*e2df9bb4SMartin Matuska dst->dds_ref_dsize += src->dds_ref_dsize; 86*e2df9bb4SMartin Matuska } 874fefe1b7SMartin Matuska 88*e2df9bb4SMartin Matuska static void 89*e2df9bb4SMartin Matuska ddt_stat_sub(ddt_stat_t *dst, const ddt_stat_t *src) 90*e2df9bb4SMartin Matuska { 91*e2df9bb4SMartin Matuska /* This caught more during development than you might expect... */ 92*e2df9bb4SMartin Matuska ASSERT3U(dst->dds_blocks, >=, src->dds_blocks); 93*e2df9bb4SMartin Matuska ASSERT3U(dst->dds_lsize, >=, src->dds_lsize); 94*e2df9bb4SMartin Matuska ASSERT3U(dst->dds_psize, >=, src->dds_psize); 95*e2df9bb4SMartin Matuska ASSERT3U(dst->dds_dsize, >=, src->dds_dsize); 96*e2df9bb4SMartin Matuska ASSERT3U(dst->dds_ref_blocks, >=, src->dds_ref_blocks); 97*e2df9bb4SMartin Matuska ASSERT3U(dst->dds_ref_lsize, >=, src->dds_ref_lsize); 98*e2df9bb4SMartin Matuska ASSERT3U(dst->dds_ref_psize, >=, src->dds_ref_psize); 99*e2df9bb4SMartin Matuska ASSERT3U(dst->dds_ref_dsize, >=, src->dds_ref_dsize); 1004fefe1b7SMartin Matuska 101*e2df9bb4SMartin Matuska dst->dds_blocks -= src->dds_blocks; 102*e2df9bb4SMartin Matuska dst->dds_lsize -= src->dds_lsize; 103*e2df9bb4SMartin Matuska dst->dds_psize -= src->dds_psize; 104*e2df9bb4SMartin Matuska dst->dds_dsize -= src->dds_dsize; 105*e2df9bb4SMartin Matuska dst->dds_ref_blocks -= src->dds_ref_blocks; 106*e2df9bb4SMartin Matuska dst->dds_ref_lsize -= src->dds_ref_lsize; 107*e2df9bb4SMartin Matuska dst->dds_ref_psize -= src->dds_ref_psize; 108*e2df9bb4SMartin Matuska dst->dds_ref_dsize -= src->dds_ref_dsize; 1094fefe1b7SMartin Matuska } 1104fefe1b7SMartin Matuska 1114fefe1b7SMartin Matuska void 112*e2df9bb4SMartin Matuska ddt_histogram_add_entry(ddt_t *ddt, ddt_histogram_t *ddh, 113*e2df9bb4SMartin Matuska const ddt_lightweight_entry_t *ddlwe) 1144fefe1b7SMartin Matuska { 1154fefe1b7SMartin Matuska ddt_stat_t dds; 1164fefe1b7SMartin Matuska int bucket; 1174fefe1b7SMartin Matuska 118*e2df9bb4SMartin Matuska ddt_stat_generate(ddt, ddlwe, &dds); 1194fefe1b7SMartin Matuska 1204fefe1b7SMartin Matuska bucket = highbit64(dds.dds_ref_blocks) - 1; 121*e2df9bb4SMartin Matuska if (bucket < 0) 122*e2df9bb4SMartin Matuska return; 1234fefe1b7SMartin Matuska 124*e2df9bb4SMartin Matuska ddt_stat_add(&ddh->ddh_stat[bucket], &dds); 125*e2df9bb4SMartin Matuska } 1264fefe1b7SMartin Matuska 127*e2df9bb4SMartin Matuska void 128*e2df9bb4SMartin Matuska ddt_histogram_sub_entry(ddt_t *ddt, ddt_histogram_t *ddh, 129*e2df9bb4SMartin Matuska const ddt_lightweight_entry_t *ddlwe) 130*e2df9bb4SMartin Matuska { 131*e2df9bb4SMartin Matuska ddt_stat_t dds; 132*e2df9bb4SMartin Matuska int bucket; 133*e2df9bb4SMartin Matuska 134*e2df9bb4SMartin Matuska ddt_stat_generate(ddt, ddlwe, &dds); 135*e2df9bb4SMartin Matuska 136*e2df9bb4SMartin Matuska bucket = highbit64(dds.dds_ref_blocks) - 1; 137*e2df9bb4SMartin Matuska if (bucket < 0) 138*e2df9bb4SMartin Matuska return; 139*e2df9bb4SMartin Matuska 140*e2df9bb4SMartin Matuska ddt_stat_sub(&ddh->ddh_stat[bucket], &dds); 1414fefe1b7SMartin Matuska } 1424fefe1b7SMartin Matuska 1434fefe1b7SMartin Matuska void 1444fefe1b7SMartin Matuska ddt_histogram_add(ddt_histogram_t *dst, const ddt_histogram_t *src) 1454fefe1b7SMartin Matuska { 1464fefe1b7SMartin Matuska for (int h = 0; h < 64; h++) 147*e2df9bb4SMartin Matuska ddt_stat_add(&dst->ddh_stat[h], &src->ddh_stat[h]); 1484fefe1b7SMartin Matuska } 1494fefe1b7SMartin Matuska 1504fefe1b7SMartin Matuska void 151*e2df9bb4SMartin Matuska ddt_histogram_total(ddt_stat_t *dds, const ddt_histogram_t *ddh) 1524fefe1b7SMartin Matuska { 1534fefe1b7SMartin Matuska memset(dds, 0, sizeof (*dds)); 1544fefe1b7SMartin Matuska 1554fefe1b7SMartin Matuska for (int h = 0; h < 64; h++) 156*e2df9bb4SMartin Matuska ddt_stat_add(dds, &ddh->ddh_stat[h]); 1574fefe1b7SMartin Matuska } 1584fefe1b7SMartin Matuska 1594fefe1b7SMartin Matuska boolean_t 1604fefe1b7SMartin Matuska ddt_histogram_empty(const ddt_histogram_t *ddh) 1614fefe1b7SMartin Matuska { 162*e2df9bb4SMartin Matuska for (int h = 0; h < 64; h++) { 163*e2df9bb4SMartin Matuska const ddt_stat_t *dds = &ddh->ddh_stat[h]; 1644fefe1b7SMartin Matuska 165*e2df9bb4SMartin Matuska if (dds->dds_blocks == 0 && 166*e2df9bb4SMartin Matuska dds->dds_lsize == 0 && 167*e2df9bb4SMartin Matuska dds->dds_psize == 0 && 168*e2df9bb4SMartin Matuska dds->dds_dsize == 0 && 169*e2df9bb4SMartin Matuska dds->dds_ref_blocks == 0 && 170*e2df9bb4SMartin Matuska dds->dds_ref_lsize == 0 && 171*e2df9bb4SMartin Matuska dds->dds_ref_psize == 0 && 172*e2df9bb4SMartin Matuska dds->dds_ref_dsize == 0) 173*e2df9bb4SMartin Matuska continue; 174*e2df9bb4SMartin Matuska 1754fefe1b7SMartin Matuska return (B_FALSE); 176*e2df9bb4SMartin Matuska } 1774fefe1b7SMartin Matuska 1784fefe1b7SMartin Matuska return (B_TRUE); 1794fefe1b7SMartin Matuska } 1804fefe1b7SMartin Matuska 1814fefe1b7SMartin Matuska void 1824fefe1b7SMartin Matuska ddt_get_dedup_object_stats(spa_t *spa, ddt_object_t *ddo_total) 1834fefe1b7SMartin Matuska { 184ce4dcb97SMartin Matuska memset(ddo_total, 0, sizeof (*ddo_total)); 185ce4dcb97SMartin Matuska 1864fefe1b7SMartin Matuska for (enum zio_checksum c = 0; c < ZIO_CHECKSUM_FUNCTIONS; c++) { 1874fefe1b7SMartin Matuska ddt_t *ddt = spa->spa_ddt[c]; 1884fefe1b7SMartin Matuska if (!ddt) 1894fefe1b7SMartin Matuska continue; 1904fefe1b7SMartin Matuska 1914fefe1b7SMartin Matuska for (ddt_type_t type = 0; type < DDT_TYPES; type++) { 1924fefe1b7SMartin Matuska for (ddt_class_t class = 0; class < DDT_CLASSES; 1934fefe1b7SMartin Matuska class++) { 194ce4dcb97SMartin Matuska dmu_object_info_t doi; 195ce4dcb97SMartin Matuska uint64_t cnt; 196ce4dcb97SMartin Matuska int err; 197ce4dcb97SMartin Matuska 198ce4dcb97SMartin Matuska /* 199ce4dcb97SMartin Matuska * These stats were originally calculated 200ce4dcb97SMartin Matuska * during ddt_object_load(). 201ce4dcb97SMartin Matuska */ 202ce4dcb97SMartin Matuska 203ce4dcb97SMartin Matuska err = ddt_object_info(ddt, type, class, &doi); 204ce4dcb97SMartin Matuska if (err != 0) 205ce4dcb97SMartin Matuska continue; 206ce4dcb97SMartin Matuska 207ce4dcb97SMartin Matuska err = ddt_object_count(ddt, type, class, &cnt); 208ce4dcb97SMartin Matuska if (err != 0) 209ce4dcb97SMartin Matuska continue; 210ce4dcb97SMartin Matuska 2114fefe1b7SMartin Matuska ddt_object_t *ddo = 2124fefe1b7SMartin Matuska &ddt->ddt_object_stats[type][class]; 213ce4dcb97SMartin Matuska 214ce4dcb97SMartin Matuska ddo->ddo_count = cnt; 215ce4dcb97SMartin Matuska ddo->ddo_dspace = 216ce4dcb97SMartin Matuska doi.doi_physical_blocks_512 << 9; 217ce4dcb97SMartin Matuska ddo->ddo_mspace = doi.doi_fill_count * 218ce4dcb97SMartin Matuska doi.doi_data_block_size; 219ce4dcb97SMartin Matuska 2204fefe1b7SMartin Matuska ddo_total->ddo_count += ddo->ddo_count; 2214fefe1b7SMartin Matuska ddo_total->ddo_dspace += ddo->ddo_dspace; 2224fefe1b7SMartin Matuska ddo_total->ddo_mspace += ddo->ddo_mspace; 2234fefe1b7SMartin Matuska } 2244fefe1b7SMartin Matuska } 225*e2df9bb4SMartin Matuska 226*e2df9bb4SMartin Matuska ddt_object_t *ddo = &ddt->ddt_log_stats; 227*e2df9bb4SMartin Matuska ddo_total->ddo_count += ddo->ddo_count; 228*e2df9bb4SMartin Matuska ddo_total->ddo_dspace += ddo->ddo_dspace; 229*e2df9bb4SMartin Matuska ddo_total->ddo_mspace += ddo->ddo_mspace; 2304fefe1b7SMartin Matuska } 2314fefe1b7SMartin Matuska 232ce4dcb97SMartin Matuska /* 233ce4dcb97SMartin Matuska * This returns raw counts (not averages). One of the consumers, 234ce4dcb97SMartin Matuska * print_dedup_stats(), historically has expected raw counts. 235ce4dcb97SMartin Matuska */ 236ce4dcb97SMartin Matuska 237ce4dcb97SMartin Matuska spa->spa_dedup_dsize = ddo_total->ddo_dspace; 2384fefe1b7SMartin Matuska } 239ce4dcb97SMartin Matuska 240ce4dcb97SMartin Matuska uint64_t 241ce4dcb97SMartin Matuska ddt_get_ddt_dsize(spa_t *spa) 242ce4dcb97SMartin Matuska { 243ce4dcb97SMartin Matuska ddt_object_t ddo_total; 244ce4dcb97SMartin Matuska 245ce4dcb97SMartin Matuska /* recalculate after each txg sync */ 246ce4dcb97SMartin Matuska if (spa->spa_dedup_dsize == ~0ULL) 247ce4dcb97SMartin Matuska ddt_get_dedup_object_stats(spa, &ddo_total); 248ce4dcb97SMartin Matuska 249ce4dcb97SMartin Matuska return (spa->spa_dedup_dsize); 2504fefe1b7SMartin Matuska } 2514fefe1b7SMartin Matuska 2524fefe1b7SMartin Matuska void 2534fefe1b7SMartin Matuska ddt_get_dedup_histogram(spa_t *spa, ddt_histogram_t *ddh) 2544fefe1b7SMartin Matuska { 2554fefe1b7SMartin Matuska for (enum zio_checksum c = 0; c < ZIO_CHECKSUM_FUNCTIONS; c++) { 2564fefe1b7SMartin Matuska ddt_t *ddt = spa->spa_ddt[c]; 2574fefe1b7SMartin Matuska if (!ddt) 2584fefe1b7SMartin Matuska continue; 2594fefe1b7SMartin Matuska 2604fefe1b7SMartin Matuska for (ddt_type_t type = 0; type < DDT_TYPES; type++) { 2614fefe1b7SMartin Matuska for (ddt_class_t class = 0; class < DDT_CLASSES; 2624fefe1b7SMartin Matuska class++) { 2634fefe1b7SMartin Matuska ddt_histogram_add(ddh, 2644fefe1b7SMartin Matuska &ddt->ddt_histogram_cache[type][class]); 2654fefe1b7SMartin Matuska } 2664fefe1b7SMartin Matuska } 267*e2df9bb4SMartin Matuska 268*e2df9bb4SMartin Matuska ddt_histogram_add(ddh, &ddt->ddt_log_histogram); 2694fefe1b7SMartin Matuska } 2704fefe1b7SMartin Matuska } 2714fefe1b7SMartin Matuska 2724fefe1b7SMartin Matuska void 2734fefe1b7SMartin Matuska ddt_get_dedup_stats(spa_t *spa, ddt_stat_t *dds_total) 2744fefe1b7SMartin Matuska { 2754fefe1b7SMartin Matuska ddt_histogram_t *ddh_total; 2764fefe1b7SMartin Matuska 2774fefe1b7SMartin Matuska ddh_total = kmem_zalloc(sizeof (ddt_histogram_t), KM_SLEEP); 2784fefe1b7SMartin Matuska ddt_get_dedup_histogram(spa, ddh_total); 279*e2df9bb4SMartin Matuska ddt_histogram_total(dds_total, ddh_total); 2804fefe1b7SMartin Matuska kmem_free(ddh_total, sizeof (ddt_histogram_t)); 2814fefe1b7SMartin Matuska } 2824fefe1b7SMartin Matuska 2834fefe1b7SMartin Matuska uint64_t 2844fefe1b7SMartin Matuska ddt_get_dedup_dspace(spa_t *spa) 2854fefe1b7SMartin Matuska { 2864fefe1b7SMartin Matuska ddt_stat_t dds_total; 2874fefe1b7SMartin Matuska 2884fefe1b7SMartin Matuska if (spa->spa_dedup_dspace != ~0ULL) 2894fefe1b7SMartin Matuska return (spa->spa_dedup_dspace); 2904fefe1b7SMartin Matuska 2914fefe1b7SMartin Matuska memset(&dds_total, 0, sizeof (ddt_stat_t)); 2924fefe1b7SMartin Matuska 2934fefe1b7SMartin Matuska /* Calculate and cache the stats */ 2944fefe1b7SMartin Matuska ddt_get_dedup_stats(spa, &dds_total); 2954fefe1b7SMartin Matuska spa->spa_dedup_dspace = dds_total.dds_ref_dsize - dds_total.dds_dsize; 2964fefe1b7SMartin Matuska return (spa->spa_dedup_dspace); 2974fefe1b7SMartin Matuska } 2984fefe1b7SMartin Matuska 2994fefe1b7SMartin Matuska uint64_t 3004fefe1b7SMartin Matuska ddt_get_pool_dedup_ratio(spa_t *spa) 3014fefe1b7SMartin Matuska { 3024fefe1b7SMartin Matuska ddt_stat_t dds_total = { 0 }; 3034fefe1b7SMartin Matuska 3044fefe1b7SMartin Matuska ddt_get_dedup_stats(spa, &dds_total); 3054fefe1b7SMartin Matuska if (dds_total.dds_dsize == 0) 3064fefe1b7SMartin Matuska return (100); 3074fefe1b7SMartin Matuska 3084fefe1b7SMartin Matuska return (dds_total.dds_ref_dsize * 100 / dds_total.dds_dsize); 3094fefe1b7SMartin Matuska } 310ce4dcb97SMartin Matuska 311ce4dcb97SMartin Matuska int 312ce4dcb97SMartin Matuska ddt_get_pool_dedup_cached(spa_t *spa, uint64_t *psize) 313ce4dcb97SMartin Matuska { 314ce4dcb97SMartin Matuska uint64_t l1sz, l1tot, l2sz, l2tot; 315ce4dcb97SMartin Matuska int err = 0; 316ce4dcb97SMartin Matuska 317ce4dcb97SMartin Matuska l1tot = l2tot = 0; 318ce4dcb97SMartin Matuska *psize = 0; 319ce4dcb97SMartin Matuska for (enum zio_checksum c = 0; c < ZIO_CHECKSUM_FUNCTIONS; c++) { 320ce4dcb97SMartin Matuska ddt_t *ddt = spa->spa_ddt[c]; 321ce4dcb97SMartin Matuska if (ddt == NULL) 322ce4dcb97SMartin Matuska continue; 323ce4dcb97SMartin Matuska for (ddt_type_t type = 0; type < DDT_TYPES; type++) { 324ce4dcb97SMartin Matuska for (ddt_class_t class = 0; class < DDT_CLASSES; 325ce4dcb97SMartin Matuska class++) { 326ce4dcb97SMartin Matuska err = dmu_object_cached_size(ddt->ddt_os, 327ce4dcb97SMartin Matuska ddt->ddt_object[type][class], &l1sz, &l2sz); 328ce4dcb97SMartin Matuska if (err != 0) 329ce4dcb97SMartin Matuska return (err); 330ce4dcb97SMartin Matuska l1tot += l1sz; 331ce4dcb97SMartin Matuska l2tot += l2sz; 332ce4dcb97SMartin Matuska } 333ce4dcb97SMartin Matuska } 334ce4dcb97SMartin Matuska } 335ce4dcb97SMartin Matuska 336ce4dcb97SMartin Matuska *psize = l1tot + l2tot; 337ce4dcb97SMartin Matuska return (err); 338ce4dcb97SMartin Matuska } 339