1 // SPDX-License-Identifier: CDDL-1.0 2 /* 3 * CDDL HEADER START 4 * 5 * The contents of this file are subject to the terms of the 6 * Common Development and Distribution License (the "License"). 7 * You may not use this file except in compliance with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or https://opensource.org/licenses/CDDL-1.0. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 25 * Copyright (c) 2012, 2016 by Delphix. All rights reserved. 26 * Copyright (c) 2022 by Pawel Jakub Dawidek 27 * Copyright (c) 2023, Klara Inc. 28 */ 29 30 #include <sys/zfs_context.h> 31 #include <sys/spa.h> 32 #include <sys/spa_impl.h> 33 #include <sys/ddt.h> 34 #include <sys/ddt_impl.h> 35 36 static void 37 ddt_stat_generate(ddt_t *ddt, const ddt_lightweight_entry_t *ddlwe, 38 ddt_stat_t *dds) 39 { 40 spa_t *spa = ddt->ddt_spa; 41 uint64_t lsize = DDK_GET_LSIZE(&ddlwe->ddlwe_key); 42 uint64_t psize = DDK_GET_PSIZE(&ddlwe->ddlwe_key); 43 44 memset(dds, 0, sizeof (*dds)); 45 46 for (int p = 0; p < DDT_NPHYS(ddt); p++) { 47 const ddt_univ_phys_t *ddp = &ddlwe->ddlwe_phys; 48 ddt_phys_variant_t v = DDT_PHYS_VARIANT(ddt, p); 49 50 if (ddt_phys_birth(ddp, v) == 0) 51 continue; 52 53 int ndvas = ddt_phys_dva_count(ddp, v, 54 DDK_GET_CRYPT(&ddlwe->ddlwe_key)); 55 const dva_t *dvas = (ddt->ddt_flags & DDT_FLAG_FLAT) ? 56 ddp->ddp_flat.ddp_dva : ddp->ddp_trad[p].ddp_dva; 57 58 uint64_t dsize = 0; 59 for (int d = 0; d < ndvas; d++) 60 dsize += dva_get_dsize_sync(spa, &dvas[d]); 61 62 uint64_t refcnt = ddt_phys_refcnt(ddp, v); 63 64 dds->dds_blocks += 1; 65 dds->dds_lsize += lsize; 66 dds->dds_psize += psize; 67 dds->dds_dsize += dsize; 68 69 dds->dds_ref_blocks += refcnt; 70 dds->dds_ref_lsize += lsize * refcnt; 71 dds->dds_ref_psize += psize * refcnt; 72 dds->dds_ref_dsize += dsize * refcnt; 73 } 74 } 75 76 static void 77 ddt_stat_add(ddt_stat_t *dst, const ddt_stat_t *src) 78 { 79 dst->dds_blocks += src->dds_blocks; 80 dst->dds_lsize += src->dds_lsize; 81 dst->dds_psize += src->dds_psize; 82 dst->dds_dsize += src->dds_dsize; 83 dst->dds_ref_blocks += src->dds_ref_blocks; 84 dst->dds_ref_lsize += src->dds_ref_lsize; 85 dst->dds_ref_psize += src->dds_ref_psize; 86 dst->dds_ref_dsize += src->dds_ref_dsize; 87 } 88 89 static void 90 ddt_stat_sub(ddt_stat_t *dst, const ddt_stat_t *src) 91 { 92 /* This caught more during development than you might expect... */ 93 ASSERT3U(dst->dds_blocks, >=, src->dds_blocks); 94 ASSERT3U(dst->dds_lsize, >=, src->dds_lsize); 95 ASSERT3U(dst->dds_psize, >=, src->dds_psize); 96 ASSERT3U(dst->dds_dsize, >=, src->dds_dsize); 97 ASSERT3U(dst->dds_ref_blocks, >=, src->dds_ref_blocks); 98 ASSERT3U(dst->dds_ref_lsize, >=, src->dds_ref_lsize); 99 ASSERT3U(dst->dds_ref_psize, >=, src->dds_ref_psize); 100 ASSERT3U(dst->dds_ref_dsize, >=, src->dds_ref_dsize); 101 102 dst->dds_blocks -= src->dds_blocks; 103 dst->dds_lsize -= src->dds_lsize; 104 dst->dds_psize -= src->dds_psize; 105 dst->dds_dsize -= src->dds_dsize; 106 dst->dds_ref_blocks -= src->dds_ref_blocks; 107 dst->dds_ref_lsize -= src->dds_ref_lsize; 108 dst->dds_ref_psize -= src->dds_ref_psize; 109 dst->dds_ref_dsize -= src->dds_ref_dsize; 110 } 111 112 void 113 ddt_histogram_add_entry(ddt_t *ddt, ddt_histogram_t *ddh, 114 const ddt_lightweight_entry_t *ddlwe) 115 { 116 ddt_stat_t dds; 117 int bucket; 118 119 ddt_stat_generate(ddt, ddlwe, &dds); 120 121 bucket = highbit64(dds.dds_ref_blocks) - 1; 122 if (bucket < 0) 123 return; 124 125 ddt_stat_add(&ddh->ddh_stat[bucket], &dds); 126 } 127 128 void 129 ddt_histogram_sub_entry(ddt_t *ddt, ddt_histogram_t *ddh, 130 const ddt_lightweight_entry_t *ddlwe) 131 { 132 ddt_stat_t dds; 133 int bucket; 134 135 ddt_stat_generate(ddt, ddlwe, &dds); 136 137 bucket = highbit64(dds.dds_ref_blocks) - 1; 138 if (bucket < 0) 139 return; 140 141 ddt_stat_sub(&ddh->ddh_stat[bucket], &dds); 142 } 143 144 void 145 ddt_histogram_add(ddt_histogram_t *dst, const ddt_histogram_t *src) 146 { 147 for (int h = 0; h < 64; h++) 148 ddt_stat_add(&dst->ddh_stat[h], &src->ddh_stat[h]); 149 } 150 151 void 152 ddt_histogram_total(ddt_stat_t *dds, const ddt_histogram_t *ddh) 153 { 154 memset(dds, 0, sizeof (*dds)); 155 156 for (int h = 0; h < 64; h++) 157 ddt_stat_add(dds, &ddh->ddh_stat[h]); 158 } 159 160 boolean_t 161 ddt_histogram_empty(const ddt_histogram_t *ddh) 162 { 163 for (int h = 0; h < 64; h++) { 164 const ddt_stat_t *dds = &ddh->ddh_stat[h]; 165 166 if (dds->dds_blocks == 0 && 167 dds->dds_lsize == 0 && 168 dds->dds_psize == 0 && 169 dds->dds_dsize == 0 && 170 dds->dds_ref_blocks == 0 && 171 dds->dds_ref_lsize == 0 && 172 dds->dds_ref_psize == 0 && 173 dds->dds_ref_dsize == 0) 174 continue; 175 176 return (B_FALSE); 177 } 178 179 return (B_TRUE); 180 } 181 182 void 183 ddt_get_dedup_object_stats(spa_t *spa, ddt_object_t *ddo_total) 184 { 185 memset(ddo_total, 0, sizeof (*ddo_total)); 186 187 for (enum zio_checksum c = 0; c < ZIO_CHECKSUM_FUNCTIONS; c++) { 188 ddt_t *ddt = spa->spa_ddt[c]; 189 if (!ddt) 190 continue; 191 192 for (ddt_type_t type = 0; type < DDT_TYPES; type++) { 193 for (ddt_class_t class = 0; class < DDT_CLASSES; 194 class++) { 195 dmu_object_info_t doi; 196 uint64_t cnt; 197 int err; 198 199 /* 200 * These stats were originally calculated 201 * during ddt_object_load(). 202 */ 203 204 err = ddt_object_info(ddt, type, class, &doi); 205 if (err != 0) 206 continue; 207 208 err = ddt_object_count(ddt, type, class, &cnt); 209 if (err != 0) 210 continue; 211 212 ddt_object_t *ddo = 213 &ddt->ddt_object_stats[type][class]; 214 215 ddo->ddo_count = cnt; 216 ddo->ddo_dspace = 217 doi.doi_physical_blocks_512 << 9; 218 ddo->ddo_mspace = doi.doi_fill_count * 219 doi.doi_data_block_size; 220 221 ddo_total->ddo_count += ddo->ddo_count; 222 ddo_total->ddo_dspace += ddo->ddo_dspace; 223 ddo_total->ddo_mspace += ddo->ddo_mspace; 224 } 225 } 226 227 ddt_object_t *ddo = &ddt->ddt_log_stats; 228 ddo_total->ddo_count += ddo->ddo_count; 229 ddo_total->ddo_dspace += ddo->ddo_dspace; 230 ddo_total->ddo_mspace += ddo->ddo_mspace; 231 } 232 233 /* 234 * This returns raw counts (not averages). One of the consumers, 235 * print_dedup_stats(), historically has expected raw counts. 236 */ 237 238 spa->spa_dedup_dsize = ddo_total->ddo_dspace; 239 } 240 241 uint64_t 242 ddt_get_ddt_dsize(spa_t *spa) 243 { 244 ddt_object_t ddo_total; 245 246 /* recalculate after each txg sync */ 247 if (spa->spa_dedup_dsize == ~0ULL) 248 ddt_get_dedup_object_stats(spa, &ddo_total); 249 250 return (spa->spa_dedup_dsize); 251 } 252 253 void 254 ddt_get_dedup_histogram(spa_t *spa, ddt_histogram_t *ddh) 255 { 256 for (enum zio_checksum c = 0; c < ZIO_CHECKSUM_FUNCTIONS; c++) { 257 ddt_t *ddt = spa->spa_ddt[c]; 258 if (!ddt) 259 continue; 260 261 for (ddt_type_t type = 0; type < DDT_TYPES; type++) { 262 for (ddt_class_t class = 0; class < DDT_CLASSES; 263 class++) { 264 ddt_histogram_add(ddh, 265 &ddt->ddt_histogram_cache[type][class]); 266 } 267 } 268 269 ddt_histogram_add(ddh, &ddt->ddt_log_histogram); 270 } 271 } 272 273 void 274 ddt_get_dedup_stats(spa_t *spa, ddt_stat_t *dds_total) 275 { 276 ddt_histogram_t *ddh_total; 277 278 ddh_total = kmem_zalloc(sizeof (ddt_histogram_t), KM_SLEEP); 279 ddt_get_dedup_histogram(spa, ddh_total); 280 ddt_histogram_total(dds_total, ddh_total); 281 kmem_free(ddh_total, sizeof (ddt_histogram_t)); 282 } 283 284 uint64_t 285 ddt_get_dedup_dspace(spa_t *spa) 286 { 287 ddt_stat_t dds_total; 288 289 if (spa->spa_dedup_dspace != ~0ULL) 290 return (spa->spa_dedup_dspace); 291 292 memset(&dds_total, 0, sizeof (ddt_stat_t)); 293 294 /* Calculate and cache the stats */ 295 ddt_get_dedup_stats(spa, &dds_total); 296 spa->spa_dedup_dspace = dds_total.dds_ref_dsize - dds_total.dds_dsize; 297 return (spa->spa_dedup_dspace); 298 } 299 300 uint64_t 301 ddt_get_pool_dedup_ratio(spa_t *spa) 302 { 303 ddt_stat_t dds_total = { 0 }; 304 305 ddt_get_dedup_stats(spa, &dds_total); 306 if (dds_total.dds_dsize == 0) 307 return (100); 308 309 return (dds_total.dds_ref_dsize * 100 / dds_total.dds_dsize); 310 } 311 312 int 313 ddt_get_pool_dedup_cached(spa_t *spa, uint64_t *psize) 314 { 315 uint64_t l1sz, l1tot, l2sz, l2tot; 316 int err = 0; 317 318 l1tot = l2tot = 0; 319 *psize = 0; 320 for (enum zio_checksum c = 0; c < ZIO_CHECKSUM_FUNCTIONS; c++) { 321 ddt_t *ddt = spa->spa_ddt[c]; 322 if (ddt == NULL) 323 continue; 324 for (ddt_type_t type = 0; type < DDT_TYPES; type++) { 325 for (ddt_class_t class = 0; class < DDT_CLASSES; 326 class++) { 327 err = dmu_object_cached_size(ddt->ddt_os, 328 ddt->ddt_object[type][class], &l1sz, &l2sz); 329 if (err != 0) 330 return (err); 331 l1tot += l1sz; 332 l2tot += l2sz; 333 } 334 } 335 } 336 337 *psize = l1tot + l2tot; 338 return (err); 339 } 340