1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright (c) 2011, 2016 by Delphix. All rights reserved. 24 * Copyright (c) 2014 Integros [integros.com] 25 * Copyright (c) 2017 Datto Inc. 26 */ 27 28 #include <sys/bpobj.h> 29 #include <sys/zfs_context.h> 30 #include <sys/refcount.h> 31 #include <sys/dsl_pool.h> 32 #include <sys/zfeature.h> 33 #include <sys/zap.h> 34 35 /* 36 * Return an empty bpobj, preferably the empty dummy one (dp_empty_bpobj). 37 */ 38 uint64_t 39 bpobj_alloc_empty(objset_t *os, int blocksize, dmu_tx_t *tx) 40 { 41 spa_t *spa = dmu_objset_spa(os); 42 dsl_pool_t *dp = dmu_objset_pool(os); 43 44 if (spa_feature_is_enabled(spa, SPA_FEATURE_EMPTY_BPOBJ)) { 45 if (!spa_feature_is_active(spa, SPA_FEATURE_EMPTY_BPOBJ)) { 46 ASSERT0(dp->dp_empty_bpobj); 47 dp->dp_empty_bpobj = 48 bpobj_alloc(os, SPA_OLD_MAXBLOCKSIZE, tx); 49 VERIFY(zap_add(os, 50 DMU_POOL_DIRECTORY_OBJECT, 51 DMU_POOL_EMPTY_BPOBJ, sizeof (uint64_t), 1, 52 &dp->dp_empty_bpobj, tx) == 0); 53 } 54 spa_feature_incr(spa, SPA_FEATURE_EMPTY_BPOBJ, tx); 55 ASSERT(dp->dp_empty_bpobj != 0); 56 return (dp->dp_empty_bpobj); 57 } else { 58 return (bpobj_alloc(os, blocksize, tx)); 59 } 60 } 61 62 void 63 bpobj_decr_empty(objset_t *os, dmu_tx_t *tx) 64 { 65 dsl_pool_t *dp = dmu_objset_pool(os); 66 67 spa_feature_decr(dmu_objset_spa(os), SPA_FEATURE_EMPTY_BPOBJ, tx); 68 if (!spa_feature_is_active(dmu_objset_spa(os), 69 SPA_FEATURE_EMPTY_BPOBJ)) { 70 VERIFY3U(0, ==, zap_remove(dp->dp_meta_objset, 71 DMU_POOL_DIRECTORY_OBJECT, 72 DMU_POOL_EMPTY_BPOBJ, tx)); 73 VERIFY3U(0, ==, dmu_object_free(os, dp->dp_empty_bpobj, tx)); 74 dp->dp_empty_bpobj = 0; 75 } 76 } 77 78 uint64_t 79 bpobj_alloc(objset_t *os, int blocksize, dmu_tx_t *tx) 80 { 81 int size; 82 83 if (spa_version(dmu_objset_spa(os)) < SPA_VERSION_BPOBJ_ACCOUNT) 84 size = BPOBJ_SIZE_V0; 85 else if (spa_version(dmu_objset_spa(os)) < SPA_VERSION_DEADLISTS) 86 size = BPOBJ_SIZE_V1; 87 else 88 size = sizeof (bpobj_phys_t); 89 90 return (dmu_object_alloc(os, DMU_OT_BPOBJ, blocksize, 91 DMU_OT_BPOBJ_HDR, size, tx)); 92 } 93 94 void 95 bpobj_free(objset_t *os, uint64_t obj, dmu_tx_t *tx) 96 { 97 int64_t i; 98 bpobj_t bpo; 99 dmu_object_info_t doi; 100 int epb; 101 dmu_buf_t *dbuf = NULL; 102 103 ASSERT(obj != dmu_objset_pool(os)->dp_empty_bpobj); 104 VERIFY3U(0, ==, bpobj_open(&bpo, os, obj)); 105 106 mutex_enter(&bpo.bpo_lock); 107 108 if (!bpo.bpo_havesubobj || bpo.bpo_phys->bpo_subobjs == 0) 109 goto out; 110 111 VERIFY3U(0, ==, dmu_object_info(os, bpo.bpo_phys->bpo_subobjs, &doi)); 112 epb = doi.doi_data_block_size / sizeof (uint64_t); 113 114 for (i = bpo.bpo_phys->bpo_num_subobjs - 1; i >= 0; i--) { 115 uint64_t *objarray; 116 uint64_t offset, blkoff; 117 118 offset = i * sizeof (uint64_t); 119 blkoff = P2PHASE(i, epb); 120 121 if (dbuf == NULL || dbuf->db_offset > offset) { 122 if (dbuf) 123 dmu_buf_rele(dbuf, FTAG); 124 VERIFY3U(0, ==, dmu_buf_hold(os, 125 bpo.bpo_phys->bpo_subobjs, offset, FTAG, &dbuf, 0)); 126 } 127 128 ASSERT3U(offset, >=, dbuf->db_offset); 129 ASSERT3U(offset, <, dbuf->db_offset + dbuf->db_size); 130 131 objarray = dbuf->db_data; 132 bpobj_free(os, objarray[blkoff], tx); 133 } 134 if (dbuf) { 135 dmu_buf_rele(dbuf, FTAG); 136 dbuf = NULL; 137 } 138 VERIFY3U(0, ==, dmu_object_free(os, bpo.bpo_phys->bpo_subobjs, tx)); 139 140 out: 141 mutex_exit(&bpo.bpo_lock); 142 bpobj_close(&bpo); 143 144 VERIFY3U(0, ==, dmu_object_free(os, obj, tx)); 145 } 146 147 int 148 bpobj_open(bpobj_t *bpo, objset_t *os, uint64_t object) 149 { 150 dmu_object_info_t doi; 151 int err; 152 153 err = dmu_object_info(os, object, &doi); 154 if (err) 155 return (err); 156 157 bzero(bpo, sizeof (*bpo)); 158 mutex_init(&bpo->bpo_lock, NULL, MUTEX_DEFAULT, NULL); 159 160 ASSERT(bpo->bpo_dbuf == NULL); 161 ASSERT(bpo->bpo_phys == NULL); 162 ASSERT(object != 0); 163 ASSERT3U(doi.doi_type, ==, DMU_OT_BPOBJ); 164 ASSERT3U(doi.doi_bonus_type, ==, DMU_OT_BPOBJ_HDR); 165 166 err = dmu_bonus_hold(os, object, bpo, &bpo->bpo_dbuf); 167 if (err) 168 return (err); 169 170 bpo->bpo_os = os; 171 bpo->bpo_object = object; 172 bpo->bpo_epb = doi.doi_data_block_size >> SPA_BLKPTRSHIFT; 173 bpo->bpo_havecomp = (doi.doi_bonus_size > BPOBJ_SIZE_V0); 174 bpo->bpo_havesubobj = (doi.doi_bonus_size > BPOBJ_SIZE_V1); 175 bpo->bpo_phys = bpo->bpo_dbuf->db_data; 176 return (0); 177 } 178 179 boolean_t 180 bpobj_is_open(const bpobj_t *bpo) 181 { 182 return (bpo->bpo_object != 0); 183 } 184 185 void 186 bpobj_close(bpobj_t *bpo) 187 { 188 /* Lame workaround for closing a bpobj that was never opened. */ 189 if (bpo->bpo_object == 0) 190 return; 191 192 dmu_buf_rele(bpo->bpo_dbuf, bpo); 193 if (bpo->bpo_cached_dbuf != NULL) 194 dmu_buf_rele(bpo->bpo_cached_dbuf, bpo); 195 bpo->bpo_dbuf = NULL; 196 bpo->bpo_phys = NULL; 197 bpo->bpo_cached_dbuf = NULL; 198 bpo->bpo_object = 0; 199 200 mutex_destroy(&bpo->bpo_lock); 201 } 202 203 static boolean_t 204 bpobj_is_empty_impl(bpobj_t *bpo) 205 { 206 ASSERT(MUTEX_HELD(&bpo->bpo_lock)); 207 return (bpo->bpo_phys->bpo_num_blkptrs == 0 && 208 (!bpo->bpo_havesubobj || bpo->bpo_phys->bpo_num_subobjs == 0)); 209 } 210 211 212 boolean_t 213 bpobj_is_empty(bpobj_t *bpo) 214 { 215 mutex_enter(&bpo->bpo_lock); 216 boolean_t is_empty = bpobj_is_empty_impl(bpo); 217 mutex_exit(&bpo->bpo_lock); 218 return (is_empty); 219 } 220 221 static int 222 bpobj_iterate_impl(bpobj_t *bpo, bpobj_itor_t func, void *arg, dmu_tx_t *tx, 223 boolean_t free) 224 { 225 dmu_object_info_t doi; 226 int epb; 227 int64_t i; 228 int err = 0; 229 dmu_buf_t *dbuf = NULL; 230 231 ASSERT(bpobj_is_open(bpo)); 232 mutex_enter(&bpo->bpo_lock); 233 234 if (free) 235 dmu_buf_will_dirty(bpo->bpo_dbuf, tx); 236 237 for (i = bpo->bpo_phys->bpo_num_blkptrs - 1; i >= 0; i--) { 238 blkptr_t *bparray; 239 blkptr_t *bp; 240 uint64_t offset, blkoff; 241 242 offset = i * sizeof (blkptr_t); 243 blkoff = P2PHASE(i, bpo->bpo_epb); 244 245 if (dbuf == NULL || dbuf->db_offset > offset) { 246 if (dbuf) 247 dmu_buf_rele(dbuf, FTAG); 248 err = dmu_buf_hold(bpo->bpo_os, bpo->bpo_object, offset, 249 FTAG, &dbuf, 0); 250 if (err) 251 break; 252 } 253 254 ASSERT3U(offset, >=, dbuf->db_offset); 255 ASSERT3U(offset, <, dbuf->db_offset + dbuf->db_size); 256 257 bparray = dbuf->db_data; 258 bp = &bparray[blkoff]; 259 err = func(arg, bp, tx); 260 if (err) 261 break; 262 if (free) { 263 bpo->bpo_phys->bpo_bytes -= 264 bp_get_dsize_sync(dmu_objset_spa(bpo->bpo_os), bp); 265 ASSERT3S(bpo->bpo_phys->bpo_bytes, >=, 0); 266 if (bpo->bpo_havecomp) { 267 bpo->bpo_phys->bpo_comp -= BP_GET_PSIZE(bp); 268 bpo->bpo_phys->bpo_uncomp -= BP_GET_UCSIZE(bp); 269 } 270 bpo->bpo_phys->bpo_num_blkptrs--; 271 ASSERT3S(bpo->bpo_phys->bpo_num_blkptrs, >=, 0); 272 } 273 } 274 if (dbuf) { 275 dmu_buf_rele(dbuf, FTAG); 276 dbuf = NULL; 277 } 278 if (free) { 279 VERIFY3U(0, ==, dmu_free_range(bpo->bpo_os, bpo->bpo_object, 280 (i + 1) * sizeof (blkptr_t), DMU_OBJECT_END, tx)); 281 } 282 if (err || !bpo->bpo_havesubobj || bpo->bpo_phys->bpo_subobjs == 0) 283 goto out; 284 285 ASSERT(bpo->bpo_havecomp); 286 err = dmu_object_info(bpo->bpo_os, bpo->bpo_phys->bpo_subobjs, &doi); 287 if (err) { 288 mutex_exit(&bpo->bpo_lock); 289 return (err); 290 } 291 ASSERT3U(doi.doi_type, ==, DMU_OT_BPOBJ_SUBOBJ); 292 epb = doi.doi_data_block_size / sizeof (uint64_t); 293 294 for (i = bpo->bpo_phys->bpo_num_subobjs - 1; i >= 0; i--) { 295 uint64_t *objarray; 296 uint64_t offset, blkoff; 297 bpobj_t sublist; 298 uint64_t used_before, comp_before, uncomp_before; 299 uint64_t used_after, comp_after, uncomp_after; 300 301 offset = i * sizeof (uint64_t); 302 blkoff = P2PHASE(i, epb); 303 304 if (dbuf == NULL || dbuf->db_offset > offset) { 305 if (dbuf) 306 dmu_buf_rele(dbuf, FTAG); 307 err = dmu_buf_hold(bpo->bpo_os, 308 bpo->bpo_phys->bpo_subobjs, offset, FTAG, &dbuf, 0); 309 if (err) 310 break; 311 } 312 313 ASSERT3U(offset, >=, dbuf->db_offset); 314 ASSERT3U(offset, <, dbuf->db_offset + dbuf->db_size); 315 316 objarray = dbuf->db_data; 317 err = bpobj_open(&sublist, bpo->bpo_os, objarray[blkoff]); 318 if (err) 319 break; 320 if (free) { 321 err = bpobj_space(&sublist, 322 &used_before, &comp_before, &uncomp_before); 323 if (err != 0) { 324 bpobj_close(&sublist); 325 break; 326 } 327 } 328 err = bpobj_iterate_impl(&sublist, func, arg, tx, free); 329 if (free) { 330 VERIFY3U(0, ==, bpobj_space(&sublist, 331 &used_after, &comp_after, &uncomp_after)); 332 bpo->bpo_phys->bpo_bytes -= used_before - used_after; 333 ASSERT3S(bpo->bpo_phys->bpo_bytes, >=, 0); 334 bpo->bpo_phys->bpo_comp -= comp_before - comp_after; 335 bpo->bpo_phys->bpo_uncomp -= 336 uncomp_before - uncomp_after; 337 } 338 339 bpobj_close(&sublist); 340 if (err) 341 break; 342 if (free) { 343 err = dmu_object_free(bpo->bpo_os, 344 objarray[blkoff], tx); 345 if (err) 346 break; 347 bpo->bpo_phys->bpo_num_subobjs--; 348 ASSERT3S(bpo->bpo_phys->bpo_num_subobjs, >=, 0); 349 } 350 } 351 if (dbuf) { 352 dmu_buf_rele(dbuf, FTAG); 353 dbuf = NULL; 354 } 355 if (free) { 356 VERIFY3U(0, ==, dmu_free_range(bpo->bpo_os, 357 bpo->bpo_phys->bpo_subobjs, 358 (i + 1) * sizeof (uint64_t), DMU_OBJECT_END, tx)); 359 } 360 361 out: 362 /* If there are no entries, there should be no bytes. */ 363 if (bpobj_is_empty_impl(bpo)) { 364 ASSERT0(bpo->bpo_phys->bpo_bytes); 365 ASSERT0(bpo->bpo_phys->bpo_comp); 366 ASSERT0(bpo->bpo_phys->bpo_uncomp); 367 } 368 369 mutex_exit(&bpo->bpo_lock); 370 return (err); 371 } 372 373 /* 374 * Iterate and remove the entries. If func returns nonzero, iteration 375 * will stop and that entry will not be removed. 376 */ 377 int 378 bpobj_iterate(bpobj_t *bpo, bpobj_itor_t func, void *arg, dmu_tx_t *tx) 379 { 380 return (bpobj_iterate_impl(bpo, func, arg, tx, B_TRUE)); 381 } 382 383 /* 384 * Iterate the entries. If func returns nonzero, iteration will stop. 385 */ 386 int 387 bpobj_iterate_nofree(bpobj_t *bpo, bpobj_itor_t func, void *arg, dmu_tx_t *tx) 388 { 389 return (bpobj_iterate_impl(bpo, func, arg, tx, B_FALSE)); 390 } 391 392 void 393 bpobj_enqueue_subobj(bpobj_t *bpo, uint64_t subobj, dmu_tx_t *tx) 394 { 395 bpobj_t subbpo; 396 uint64_t used, comp, uncomp, subsubobjs; 397 398 ASSERT(bpobj_is_open(bpo)); 399 ASSERT(subobj != 0); 400 ASSERT(bpo->bpo_havesubobj); 401 ASSERT(bpo->bpo_havecomp); 402 ASSERT(bpo->bpo_object != dmu_objset_pool(bpo->bpo_os)->dp_empty_bpobj); 403 404 if (subobj == dmu_objset_pool(bpo->bpo_os)->dp_empty_bpobj) { 405 bpobj_decr_empty(bpo->bpo_os, tx); 406 return; 407 } 408 409 VERIFY3U(0, ==, bpobj_open(&subbpo, bpo->bpo_os, subobj)); 410 VERIFY3U(0, ==, bpobj_space(&subbpo, &used, &comp, &uncomp)); 411 412 if (bpobj_is_empty(&subbpo)) { 413 /* No point in having an empty subobj. */ 414 bpobj_close(&subbpo); 415 bpobj_free(bpo->bpo_os, subobj, tx); 416 return; 417 } 418 419 mutex_enter(&bpo->bpo_lock); 420 dmu_buf_will_dirty(bpo->bpo_dbuf, tx); 421 if (bpo->bpo_phys->bpo_subobjs == 0) { 422 bpo->bpo_phys->bpo_subobjs = dmu_object_alloc(bpo->bpo_os, 423 DMU_OT_BPOBJ_SUBOBJ, SPA_OLD_MAXBLOCKSIZE, 424 DMU_OT_NONE, 0, tx); 425 } 426 427 dmu_object_info_t doi; 428 ASSERT0(dmu_object_info(bpo->bpo_os, bpo->bpo_phys->bpo_subobjs, &doi)); 429 ASSERT3U(doi.doi_type, ==, DMU_OT_BPOBJ_SUBOBJ); 430 431 dmu_write(bpo->bpo_os, bpo->bpo_phys->bpo_subobjs, 432 bpo->bpo_phys->bpo_num_subobjs * sizeof (subobj), 433 sizeof (subobj), &subobj, tx); 434 bpo->bpo_phys->bpo_num_subobjs++; 435 436 /* 437 * If subobj has only one block of subobjs, then move subobj's 438 * subobjs to bpo's subobj list directly. This reduces 439 * recursion in bpobj_iterate due to nested subobjs. 440 */ 441 subsubobjs = subbpo.bpo_phys->bpo_subobjs; 442 if (subsubobjs != 0) { 443 dmu_object_info_t doi; 444 445 VERIFY3U(0, ==, dmu_object_info(bpo->bpo_os, subsubobjs, &doi)); 446 if (doi.doi_max_offset == doi.doi_data_block_size) { 447 dmu_buf_t *subdb; 448 uint64_t numsubsub = subbpo.bpo_phys->bpo_num_subobjs; 449 450 VERIFY3U(0, ==, dmu_buf_hold(bpo->bpo_os, subsubobjs, 451 0, FTAG, &subdb, 0)); 452 /* 453 * Make sure that we are not asking dmu_write() 454 * to write more data than we have in our buffer. 455 */ 456 VERIFY3U(subdb->db_size, >=, 457 numsubsub * sizeof (subobj)); 458 dmu_write(bpo->bpo_os, bpo->bpo_phys->bpo_subobjs, 459 bpo->bpo_phys->bpo_num_subobjs * sizeof (subobj), 460 numsubsub * sizeof (subobj), subdb->db_data, tx); 461 dmu_buf_rele(subdb, FTAG); 462 bpo->bpo_phys->bpo_num_subobjs += numsubsub; 463 464 dmu_buf_will_dirty(subbpo.bpo_dbuf, tx); 465 subbpo.bpo_phys->bpo_subobjs = 0; 466 VERIFY3U(0, ==, dmu_object_free(bpo->bpo_os, 467 subsubobjs, tx)); 468 } 469 } 470 bpo->bpo_phys->bpo_bytes += used; 471 bpo->bpo_phys->bpo_comp += comp; 472 bpo->bpo_phys->bpo_uncomp += uncomp; 473 mutex_exit(&bpo->bpo_lock); 474 475 bpobj_close(&subbpo); 476 } 477 478 void 479 bpobj_enqueue(bpobj_t *bpo, const blkptr_t *bp, dmu_tx_t *tx) 480 { 481 blkptr_t stored_bp = *bp; 482 uint64_t offset; 483 int blkoff; 484 blkptr_t *bparray; 485 486 ASSERT(bpobj_is_open(bpo)); 487 ASSERT(!BP_IS_HOLE(bp)); 488 ASSERT(bpo->bpo_object != dmu_objset_pool(bpo->bpo_os)->dp_empty_bpobj); 489 490 if (BP_IS_EMBEDDED(bp)) { 491 /* 492 * The bpobj will compress better without the payload. 493 * 494 * Note that we store EMBEDDED bp's because they have an 495 * uncompressed size, which must be accounted for. An 496 * alternative would be to add their size to bpo_uncomp 497 * without storing the bp, but that would create additional 498 * complications: bpo_uncomp would be inconsistent with the 499 * set of BP's stored, and bpobj_iterate() wouldn't visit 500 * all the space accounted for in the bpobj. 501 */ 502 bzero(&stored_bp, sizeof (stored_bp)); 503 stored_bp.blk_prop = bp->blk_prop; 504 stored_bp.blk_birth = bp->blk_birth; 505 } else if (!BP_GET_DEDUP(bp)) { 506 /* The bpobj will compress better without the checksum */ 507 bzero(&stored_bp.blk_cksum, sizeof (stored_bp.blk_cksum)); 508 } 509 510 /* We never need the fill count. */ 511 stored_bp.blk_fill = 0; 512 513 mutex_enter(&bpo->bpo_lock); 514 515 offset = bpo->bpo_phys->bpo_num_blkptrs * sizeof (stored_bp); 516 blkoff = P2PHASE(bpo->bpo_phys->bpo_num_blkptrs, bpo->bpo_epb); 517 518 if (bpo->bpo_cached_dbuf == NULL || 519 offset < bpo->bpo_cached_dbuf->db_offset || 520 offset >= bpo->bpo_cached_dbuf->db_offset + 521 bpo->bpo_cached_dbuf->db_size) { 522 if (bpo->bpo_cached_dbuf) 523 dmu_buf_rele(bpo->bpo_cached_dbuf, bpo); 524 VERIFY3U(0, ==, dmu_buf_hold(bpo->bpo_os, bpo->bpo_object, 525 offset, bpo, &bpo->bpo_cached_dbuf, 0)); 526 } 527 528 dmu_buf_will_dirty(bpo->bpo_cached_dbuf, tx); 529 bparray = bpo->bpo_cached_dbuf->db_data; 530 bparray[blkoff] = stored_bp; 531 532 dmu_buf_will_dirty(bpo->bpo_dbuf, tx); 533 bpo->bpo_phys->bpo_num_blkptrs++; 534 bpo->bpo_phys->bpo_bytes += 535 bp_get_dsize_sync(dmu_objset_spa(bpo->bpo_os), bp); 536 if (bpo->bpo_havecomp) { 537 bpo->bpo_phys->bpo_comp += BP_GET_PSIZE(bp); 538 bpo->bpo_phys->bpo_uncomp += BP_GET_UCSIZE(bp); 539 } 540 mutex_exit(&bpo->bpo_lock); 541 } 542 543 struct space_range_arg { 544 spa_t *spa; 545 uint64_t mintxg; 546 uint64_t maxtxg; 547 uint64_t used; 548 uint64_t comp; 549 uint64_t uncomp; 550 }; 551 552 /* ARGSUSED */ 553 static int 554 space_range_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx) 555 { 556 struct space_range_arg *sra = arg; 557 558 if (bp->blk_birth > sra->mintxg && bp->blk_birth <= sra->maxtxg) { 559 if (dsl_pool_sync_context(spa_get_dsl(sra->spa))) 560 sra->used += bp_get_dsize_sync(sra->spa, bp); 561 else 562 sra->used += bp_get_dsize(sra->spa, bp); 563 sra->comp += BP_GET_PSIZE(bp); 564 sra->uncomp += BP_GET_UCSIZE(bp); 565 } 566 return (0); 567 } 568 569 int 570 bpobj_space(bpobj_t *bpo, uint64_t *usedp, uint64_t *compp, uint64_t *uncompp) 571 { 572 ASSERT(bpobj_is_open(bpo)); 573 mutex_enter(&bpo->bpo_lock); 574 575 *usedp = bpo->bpo_phys->bpo_bytes; 576 if (bpo->bpo_havecomp) { 577 *compp = bpo->bpo_phys->bpo_comp; 578 *uncompp = bpo->bpo_phys->bpo_uncomp; 579 mutex_exit(&bpo->bpo_lock); 580 return (0); 581 } else { 582 mutex_exit(&bpo->bpo_lock); 583 return (bpobj_space_range(bpo, 0, UINT64_MAX, 584 usedp, compp, uncompp)); 585 } 586 } 587 588 /* 589 * Return the amount of space in the bpobj which is: 590 * mintxg < blk_birth <= maxtxg 591 */ 592 int 593 bpobj_space_range(bpobj_t *bpo, uint64_t mintxg, uint64_t maxtxg, 594 uint64_t *usedp, uint64_t *compp, uint64_t *uncompp) 595 { 596 struct space_range_arg sra = { 0 }; 597 int err; 598 599 ASSERT(bpobj_is_open(bpo)); 600 601 /* 602 * As an optimization, if they want the whole txg range, just 603 * get bpo_bytes rather than iterating over the bps. 604 */ 605 if (mintxg < TXG_INITIAL && maxtxg == UINT64_MAX && bpo->bpo_havecomp) 606 return (bpobj_space(bpo, usedp, compp, uncompp)); 607 608 sra.spa = dmu_objset_spa(bpo->bpo_os); 609 sra.mintxg = mintxg; 610 sra.maxtxg = maxtxg; 611 612 err = bpobj_iterate_nofree(bpo, space_range_cb, &sra, NULL); 613 *usedp = sra.used; 614 *compp = sra.comp; 615 *uncompp = sra.uncomp; 616 return (err); 617 } 618