FreeBSD ZFS
The Zettabyte File System

bpobj.c

Go to the documentation of this file.
00001 /*
00002  * CDDL HEADER START
00003  *
00004  * The contents of this file are subject to the terms of the
00005  * Common Development and Distribution License (the "License").
00006  * You may not use this file except in compliance with the License.
00007  *
00008  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
00009  * or http://www.opensolaris.org/os/licensing.
00010  * See the License for the specific language governing permissions
00011  * and limitations under the License.
00012  *
00013  * When distributing Covered Code, include this CDDL HEADER in each
00014  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
00015  * If applicable, add the following below this CDDL HEADER, with the
00016  * fields enclosed by brackets "[]" replaced with your own identifying
00017  * information: Portions Copyright [yyyy] [name of copyright owner]
00018  *
00019  * CDDL HEADER END
00020  */
00021 /*
00022  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
00023  * Copyright (c) 2012 by Delphix. All rights reserved.
00024  */
00025 
00026 #include <sys/bpobj.h>
00027 #include <sys/zfs_context.h>
00028 #include <sys/refcount.h>
00029 #include <sys/dsl_pool.h>
00030 #include <sys/zfeature.h>
00031 #include <sys/zap.h>
00032 
00036 uint64_t
00037 bpobj_alloc_empty(objset_t *os, int blocksize, dmu_tx_t *tx)
00038 {
00039         zfeature_info_t *empty_bpobj_feat =
00040             &spa_feature_table[SPA_FEATURE_EMPTY_BPOBJ];
00041         spa_t *spa = dmu_objset_spa(os);
00042         dsl_pool_t *dp = dmu_objset_pool(os);
00043 
00044         if (spa_feature_is_enabled(spa, empty_bpobj_feat)) {
00045                 if (!spa_feature_is_active(spa, empty_bpobj_feat)) {
00046                         ASSERT0(dp->dp_empty_bpobj);
00047                         dp->dp_empty_bpobj =
00048                             bpobj_alloc(os, SPA_MAXBLOCKSIZE, tx);
00049                         VERIFY(zap_add(os,
00050                             DMU_POOL_DIRECTORY_OBJECT,
00051                             DMU_POOL_EMPTY_BPOBJ, sizeof (uint64_t), 1,
00052                             &dp->dp_empty_bpobj, tx) == 0);
00053                 }
00054                 spa_feature_incr(spa, empty_bpobj_feat, tx);
00055                 ASSERT(dp->dp_empty_bpobj != 0);
00056                 return (dp->dp_empty_bpobj);
00057         } else {
00058                 return (bpobj_alloc(os, blocksize, tx));
00059         }
00060 }
00061 
00062 void
00063 bpobj_decr_empty(objset_t *os, dmu_tx_t *tx)
00064 {
00065         zfeature_info_t *empty_bpobj_feat =
00066             &spa_feature_table[SPA_FEATURE_EMPTY_BPOBJ];
00067         dsl_pool_t *dp = dmu_objset_pool(os);
00068 
00069         spa_feature_decr(dmu_objset_spa(os), empty_bpobj_feat, tx);
00070         if (!spa_feature_is_active(dmu_objset_spa(os), empty_bpobj_feat)) {
00071                 VERIFY3U(0, ==, zap_remove(dp->dp_meta_objset,
00072                     DMU_POOL_DIRECTORY_OBJECT,
00073                     DMU_POOL_EMPTY_BPOBJ, tx));
00074                 VERIFY3U(0, ==, dmu_object_free(os, dp->dp_empty_bpobj, tx));
00075                 dp->dp_empty_bpobj = 0;
00076         }
00077 }
00078 
00079 uint64_t
00080 bpobj_alloc(objset_t *os, int blocksize, dmu_tx_t *tx)
00081 {
00082         int size;
00083 
00084         if (spa_version(dmu_objset_spa(os)) < SPA_VERSION_BPOBJ_ACCOUNT)
00085                 size = BPOBJ_SIZE_V0;
00086         else if (spa_version(dmu_objset_spa(os)) < SPA_VERSION_DEADLISTS)
00087                 size = BPOBJ_SIZE_V1;
00088         else
00089                 size = sizeof (bpobj_phys_t);
00090 
00091         return (dmu_object_alloc(os, DMU_OT_BPOBJ, blocksize,
00092             DMU_OT_BPOBJ_HDR, size, tx));
00093 }
00094 
00095 void
00096 bpobj_free(objset_t *os, uint64_t obj, dmu_tx_t *tx)
00097 {
00098         int64_t i;
00099         bpobj_t bpo;
00100         dmu_object_info_t doi;
00101         int epb;
00102         dmu_buf_t *dbuf = NULL;
00103 
00104         ASSERT(obj != dmu_objset_pool(os)->dp_empty_bpobj);
00105         VERIFY3U(0, ==, bpobj_open(&bpo, os, obj));
00106 
00107         mutex_enter(&bpo.bpo_lock);
00108 
00109         if (!bpo.bpo_havesubobj || bpo.bpo_phys->bpo_subobjs == 0)
00110                 goto out;
00111 
00112         VERIFY3U(0, ==, dmu_object_info(os, bpo.bpo_phys->bpo_subobjs, &doi));
00113         epb = doi.doi_data_block_size / sizeof (uint64_t);
00114 
00115         for (i = bpo.bpo_phys->bpo_num_subobjs - 1; i >= 0; i--) {
00116                 uint64_t *objarray;
00117                 uint64_t offset, blkoff;
00118 
00119                 offset = i * sizeof (uint64_t);
00120                 blkoff = P2PHASE(i, epb);
00121 
00122                 if (dbuf == NULL || dbuf->db_offset > offset) {
00123                         if (dbuf)
00124                                 dmu_buf_rele(dbuf, FTAG);
00125                         VERIFY3U(0, ==, dmu_buf_hold(os,
00126                             bpo.bpo_phys->bpo_subobjs, offset, FTAG, &dbuf, 0));
00127                 }
00128 
00129                 ASSERT3U(offset, >=, dbuf->db_offset);
00130                 ASSERT3U(offset, <, dbuf->db_offset + dbuf->db_size);
00131 
00132                 objarray = dbuf->db_data;
00133                 bpobj_free(os, objarray[blkoff], tx);
00134         }
00135         if (dbuf) {
00136                 dmu_buf_rele(dbuf, FTAG);
00137                 dbuf = NULL;
00138         }
00139         VERIFY3U(0, ==, dmu_object_free(os, bpo.bpo_phys->bpo_subobjs, tx));
00140 
00141 out:
00142         mutex_exit(&bpo.bpo_lock);
00143         bpobj_close(&bpo);
00144 
00145         VERIFY3U(0, ==, dmu_object_free(os, obj, tx));
00146 }
00147 
00148 int
00149 bpobj_open(bpobj_t *bpo, objset_t *os, uint64_t object)
00150 {
00151         dmu_object_info_t doi;
00152         int err;
00153 
00154         err = dmu_object_info(os, object, &doi);
00155         if (err)
00156                 return (err);
00157 
00158         bzero(bpo, sizeof (*bpo));
00159         mutex_init(&bpo->bpo_lock, NULL, MUTEX_DEFAULT, NULL);
00160 
00161         ASSERT(bpo->bpo_dbuf == NULL);
00162         ASSERT(bpo->bpo_phys == NULL);
00163         ASSERT(object != 0);
00164         ASSERT3U(doi.doi_type, ==, DMU_OT_BPOBJ);
00165         ASSERT3U(doi.doi_bonus_type, ==, DMU_OT_BPOBJ_HDR);
00166 
00167         err = dmu_bonus_hold(os, object, bpo, &bpo->bpo_dbuf);
00168         if (err)
00169                 return (err);
00170 
00171         bpo->bpo_os = os;
00172         bpo->bpo_object = object;
00173         bpo->bpo_epb = doi.doi_data_block_size >> SPA_BLKPTRSHIFT;
00174         bpo->bpo_havecomp = (doi.doi_bonus_size > BPOBJ_SIZE_V0);
00175         bpo->bpo_havesubobj = (doi.doi_bonus_size > BPOBJ_SIZE_V1);
00176         bpo->bpo_phys = bpo->bpo_dbuf->db_data;
00177         return (0);
00178 }
00179 
00180 void
00181 bpobj_close(bpobj_t *bpo)
00182 {
00183         /* Lame workaround for closing a bpobj that was never opened. */
00184         if (bpo->bpo_object == 0)
00185                 return;
00186 
00187         dmu_buf_rele(bpo->bpo_dbuf, bpo);
00188         if (bpo->bpo_cached_dbuf != NULL)
00189                 dmu_buf_rele(bpo->bpo_cached_dbuf, bpo);
00190         bpo->bpo_dbuf = NULL;
00191         bpo->bpo_phys = NULL;
00192         bpo->bpo_cached_dbuf = NULL;
00193         bpo->bpo_object = 0;
00194 
00195         mutex_destroy(&bpo->bpo_lock);
00196 }
00197 
00198 static int
00199 bpobj_iterate_impl(bpobj_t *bpo, bpobj_itor_t func, void *arg, dmu_tx_t *tx,
00200     boolean_t free)
00201 {
00202         dmu_object_info_t doi;
00203         int epb;
00204         int64_t i;
00205         int err = 0;
00206         dmu_buf_t *dbuf = NULL;
00207 
00208         mutex_enter(&bpo->bpo_lock);
00209 
00210         if (free)
00211                 dmu_buf_will_dirty(bpo->bpo_dbuf, tx);
00212 
00213         for (i = bpo->bpo_phys->bpo_num_blkptrs - 1; i >= 0; i--) {
00214                 blkptr_t *bparray;
00215                 blkptr_t *bp;
00216                 uint64_t offset, blkoff;
00217 
00218                 offset = i * sizeof (blkptr_t);
00219                 blkoff = P2PHASE(i, bpo->bpo_epb);
00220 
00221                 if (dbuf == NULL || dbuf->db_offset > offset) {
00222                         if (dbuf)
00223                                 dmu_buf_rele(dbuf, FTAG);
00224                         err = dmu_buf_hold(bpo->bpo_os, bpo->bpo_object, offset,
00225                             FTAG, &dbuf, 0);
00226                         if (err)
00227                                 break;
00228                 }
00229 
00230                 ASSERT3U(offset, >=, dbuf->db_offset);
00231                 ASSERT3U(offset, <, dbuf->db_offset + dbuf->db_size);
00232 
00233                 bparray = dbuf->db_data;
00234                 bp = &bparray[blkoff];
00235                 err = func(arg, bp, tx);
00236                 if (err)
00237                         break;
00238                 if (free) {
00239                         bpo->bpo_phys->bpo_bytes -=
00240                             bp_get_dsize_sync(dmu_objset_spa(bpo->bpo_os), bp);
00241                         ASSERT3S(bpo->bpo_phys->bpo_bytes, >=, 0);
00242                         if (bpo->bpo_havecomp) {
00243                                 bpo->bpo_phys->bpo_comp -= BP_GET_PSIZE(bp);
00244                                 bpo->bpo_phys->bpo_uncomp -= BP_GET_UCSIZE(bp);
00245                         }
00246                         bpo->bpo_phys->bpo_num_blkptrs--;
00247                         ASSERT3S(bpo->bpo_phys->bpo_num_blkptrs, >=, 0);
00248                 }
00249         }
00250         if (dbuf) {
00251                 dmu_buf_rele(dbuf, FTAG);
00252                 dbuf = NULL;
00253         }
00254         if (free) {
00255                 i++;
00256                 VERIFY3U(0, ==, dmu_free_range(bpo->bpo_os, bpo->bpo_object,
00257                     i * sizeof (blkptr_t), -1ULL, tx));
00258         }
00259         if (err || !bpo->bpo_havesubobj || bpo->bpo_phys->bpo_subobjs == 0)
00260                 goto out;
00261 
00262         ASSERT(bpo->bpo_havecomp);
00263         err = dmu_object_info(bpo->bpo_os, bpo->bpo_phys->bpo_subobjs, &doi);
00264         if (err) {
00265                 mutex_exit(&bpo->bpo_lock);
00266                 return (err);
00267         }
00268         epb = doi.doi_data_block_size / sizeof (uint64_t);
00269 
00270         for (i = bpo->bpo_phys->bpo_num_subobjs - 1; i >= 0; i--) {
00271                 uint64_t *objarray;
00272                 uint64_t offset, blkoff;
00273                 bpobj_t sublist;
00274                 uint64_t used_before, comp_before, uncomp_before;
00275                 uint64_t used_after, comp_after, uncomp_after;
00276 
00277                 offset = i * sizeof (uint64_t);
00278                 blkoff = P2PHASE(i, epb);
00279 
00280                 if (dbuf == NULL || dbuf->db_offset > offset) {
00281                         if (dbuf)
00282                                 dmu_buf_rele(dbuf, FTAG);
00283                         err = dmu_buf_hold(bpo->bpo_os,
00284                             bpo->bpo_phys->bpo_subobjs, offset, FTAG, &dbuf, 0);
00285                         if (err)
00286                                 break;
00287                 }
00288 
00289                 ASSERT3U(offset, >=, dbuf->db_offset);
00290                 ASSERT3U(offset, <, dbuf->db_offset + dbuf->db_size);
00291 
00292                 objarray = dbuf->db_data;
00293                 err = bpobj_open(&sublist, bpo->bpo_os, objarray[blkoff]);
00294                 if (err)
00295                         break;
00296                 if (free) {
00297                         err = bpobj_space(&sublist,
00298                             &used_before, &comp_before, &uncomp_before);
00299                         if (err)
00300                                 break;
00301                 }
00302                 err = bpobj_iterate_impl(&sublist, func, arg, tx, free);
00303                 if (free) {
00304                         VERIFY3U(0, ==, bpobj_space(&sublist,
00305                             &used_after, &comp_after, &uncomp_after));
00306                         bpo->bpo_phys->bpo_bytes -= used_before - used_after;
00307                         ASSERT3S(bpo->bpo_phys->bpo_bytes, >=, 0);
00308                         bpo->bpo_phys->bpo_comp -= comp_before - comp_after;
00309                         bpo->bpo_phys->bpo_uncomp -=
00310                             uncomp_before - uncomp_after;
00311                 }
00312 
00313                 bpobj_close(&sublist);
00314                 if (err)
00315                         break;
00316                 if (free) {
00317                         err = dmu_object_free(bpo->bpo_os,
00318                             objarray[blkoff], tx);
00319                         if (err)
00320                                 break;
00321                         bpo->bpo_phys->bpo_num_subobjs--;
00322                         ASSERT3S(bpo->bpo_phys->bpo_num_subobjs, >=, 0);
00323                 }
00324         }
00325         if (dbuf) {
00326                 dmu_buf_rele(dbuf, FTAG);
00327                 dbuf = NULL;
00328         }
00329         if (free) {
00330                 VERIFY3U(0, ==, dmu_free_range(bpo->bpo_os,
00331                     bpo->bpo_phys->bpo_subobjs,
00332                     (i + 1) * sizeof (uint64_t), -1ULL, tx));
00333         }
00334 
00335 out:
00336         /* If there are no entries, there should be no bytes. */
00337         ASSERT(bpo->bpo_phys->bpo_num_blkptrs > 0 ||
00338             (bpo->bpo_havesubobj && bpo->bpo_phys->bpo_num_subobjs > 0) ||
00339             bpo->bpo_phys->bpo_bytes == 0);
00340 
00341         mutex_exit(&bpo->bpo_lock);
00342         return (err);
00343 }
00344 
00349 int
00350 bpobj_iterate(bpobj_t *bpo, bpobj_itor_t func, void *arg, dmu_tx_t *tx)
00351 {
00352         return (bpobj_iterate_impl(bpo, func, arg, tx, B_TRUE));
00353 }
00354 
00358 int
00359 bpobj_iterate_nofree(bpobj_t *bpo, bpobj_itor_t func, void *arg, dmu_tx_t *tx)
00360 {
00361         return (bpobj_iterate_impl(bpo, func, arg, tx, B_FALSE));
00362 }
00363 
00364 void
00365 bpobj_enqueue_subobj(bpobj_t *bpo, uint64_t subobj, dmu_tx_t *tx)
00366 {
00367         bpobj_t subbpo;
00368         uint64_t used, comp, uncomp, subsubobjs;
00369 
00370         ASSERT(bpo->bpo_havesubobj);
00371         ASSERT(bpo->bpo_havecomp);
00372         ASSERT(bpo->bpo_object != dmu_objset_pool(bpo->bpo_os)->dp_empty_bpobj);
00373 
00374         if (subobj == dmu_objset_pool(bpo->bpo_os)->dp_empty_bpobj) {
00375                 bpobj_decr_empty(bpo->bpo_os, tx);
00376                 return;
00377         }
00378 
00379         VERIFY3U(0, ==, bpobj_open(&subbpo, bpo->bpo_os, subobj));
00380         VERIFY3U(0, ==, bpobj_space(&subbpo, &used, &comp, &uncomp));
00381 
00382         if (used == 0) {
00383                 /* No point in having an empty subobj. */
00384                 bpobj_close(&subbpo);
00385                 bpobj_free(bpo->bpo_os, subobj, tx);
00386                 return;
00387         }
00388 
00389         dmu_buf_will_dirty(bpo->bpo_dbuf, tx);
00390         if (bpo->bpo_phys->bpo_subobjs == 0) {
00391                 bpo->bpo_phys->bpo_subobjs = dmu_object_alloc(bpo->bpo_os,
00392                     DMU_OT_BPOBJ_SUBOBJ, SPA_MAXBLOCKSIZE, DMU_OT_NONE, 0, tx);
00393         }
00394 
00395         mutex_enter(&bpo->bpo_lock);
00396         dmu_write(bpo->bpo_os, bpo->bpo_phys->bpo_subobjs,
00397             bpo->bpo_phys->bpo_num_subobjs * sizeof (subobj),
00398             sizeof (subobj), &subobj, tx);
00399         bpo->bpo_phys->bpo_num_subobjs++;
00400 
00401         /*
00402          * If subobj has only one block of subobjs, then move subobj's
00403          * subobjs to bpo's subobj list directly.  This reduces
00404          * recursion in bpobj_iterate due to nested subobjs.
00405          */
00406         subsubobjs = subbpo.bpo_phys->bpo_subobjs;
00407         if (subsubobjs != 0) {
00408                 dmu_object_info_t doi;
00409 
00410                 VERIFY3U(0, ==, dmu_object_info(bpo->bpo_os, subsubobjs, &doi));
00411                 if (doi.doi_max_offset == doi.doi_data_block_size) {
00412                         dmu_buf_t *subdb;
00413                         uint64_t numsubsub = subbpo.bpo_phys->bpo_num_subobjs;
00414 
00415                         VERIFY3U(0, ==, dmu_buf_hold(bpo->bpo_os, subsubobjs,
00416                             0, FTAG, &subdb, 0));
00417                         dmu_write(bpo->bpo_os, bpo->bpo_phys->bpo_subobjs,
00418                             bpo->bpo_phys->bpo_num_subobjs * sizeof (subobj),
00419                             numsubsub * sizeof (subobj), subdb->db_data, tx);
00420                         dmu_buf_rele(subdb, FTAG);
00421                         bpo->bpo_phys->bpo_num_subobjs += numsubsub;
00422 
00423                         dmu_buf_will_dirty(subbpo.bpo_dbuf, tx);
00424                         subbpo.bpo_phys->bpo_subobjs = 0;
00425                         VERIFY3U(0, ==, dmu_object_free(bpo->bpo_os,
00426                             subsubobjs, tx));
00427                 }
00428         }
00429         bpo->bpo_phys->bpo_bytes += used;
00430         bpo->bpo_phys->bpo_comp += comp;
00431         bpo->bpo_phys->bpo_uncomp += uncomp;
00432         mutex_exit(&bpo->bpo_lock);
00433 
00434         bpobj_close(&subbpo);
00435 }
00436 
00437 void
00438 bpobj_enqueue(bpobj_t *bpo, const blkptr_t *bp, dmu_tx_t *tx)
00439 {
00440         blkptr_t stored_bp = *bp;
00441         uint64_t offset;
00442         int blkoff;
00443         blkptr_t *bparray;
00444 
00445         ASSERT(!BP_IS_HOLE(bp));
00446         ASSERT(bpo->bpo_object != dmu_objset_pool(bpo->bpo_os)->dp_empty_bpobj);
00447 
00448         /* We never need the fill count. */
00449         stored_bp.blk_fill = 0;
00450 
00451         /* The bpobj will compress better if we can leave off the checksum */
00452         if (!BP_GET_DEDUP(bp))
00453                 bzero(&stored_bp.blk_cksum, sizeof (stored_bp.blk_cksum));
00454 
00455         mutex_enter(&bpo->bpo_lock);
00456 
00457         offset = bpo->bpo_phys->bpo_num_blkptrs * sizeof (stored_bp);
00458         blkoff = P2PHASE(bpo->bpo_phys->bpo_num_blkptrs, bpo->bpo_epb);
00459 
00460         if (bpo->bpo_cached_dbuf == NULL ||
00461             offset < bpo->bpo_cached_dbuf->db_offset ||
00462             offset >= bpo->bpo_cached_dbuf->db_offset +
00463             bpo->bpo_cached_dbuf->db_size) {
00464                 if (bpo->bpo_cached_dbuf)
00465                         dmu_buf_rele(bpo->bpo_cached_dbuf, bpo);
00466                 VERIFY3U(0, ==, dmu_buf_hold(bpo->bpo_os, bpo->bpo_object,
00467                     offset, bpo, &bpo->bpo_cached_dbuf, 0));
00468         }
00469 
00470         dmu_buf_will_dirty(bpo->bpo_cached_dbuf, tx);
00471         bparray = bpo->bpo_cached_dbuf->db_data;
00472         bparray[blkoff] = stored_bp;
00473 
00474         dmu_buf_will_dirty(bpo->bpo_dbuf, tx);
00475         bpo->bpo_phys->bpo_num_blkptrs++;
00476         bpo->bpo_phys->bpo_bytes +=
00477             bp_get_dsize_sync(dmu_objset_spa(bpo->bpo_os), bp);
00478         if (bpo->bpo_havecomp) {
00479                 bpo->bpo_phys->bpo_comp += BP_GET_PSIZE(bp);
00480                 bpo->bpo_phys->bpo_uncomp += BP_GET_UCSIZE(bp);
00481         }
00482         mutex_exit(&bpo->bpo_lock);
00483 }
00484 
00485 struct space_range_arg {
00486         spa_t *spa;
00487         uint64_t mintxg;
00488         uint64_t maxtxg;
00489         uint64_t used;
00490         uint64_t comp;
00491         uint64_t uncomp;
00492 };
00493 
00494 /* ARGSUSED */
00495 static int
00496 space_range_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx)
00497 {
00498         struct space_range_arg *sra = arg;
00499 
00500         if (bp->blk_birth > sra->mintxg && bp->blk_birth <= sra->maxtxg) {
00501                 if (dsl_pool_sync_context(spa_get_dsl(sra->spa)))
00502                         sra->used += bp_get_dsize_sync(sra->spa, bp);
00503                 else
00504                         sra->used += bp_get_dsize(sra->spa, bp);
00505                 sra->comp += BP_GET_PSIZE(bp);
00506                 sra->uncomp += BP_GET_UCSIZE(bp);
00507         }
00508         return (0);
00509 }
00510 
00511 int
00512 bpobj_space(bpobj_t *bpo, uint64_t *usedp, uint64_t *compp, uint64_t *uncompp)
00513 {
00514         mutex_enter(&bpo->bpo_lock);
00515 
00516         *usedp = bpo->bpo_phys->bpo_bytes;
00517         if (bpo->bpo_havecomp) {
00518                 *compp = bpo->bpo_phys->bpo_comp;
00519                 *uncompp = bpo->bpo_phys->bpo_uncomp;
00520                 mutex_exit(&bpo->bpo_lock);
00521                 return (0);
00522         } else {
00523                 mutex_exit(&bpo->bpo_lock);
00524                 return (bpobj_space_range(bpo, 0, UINT64_MAX,
00525                     usedp, compp, uncompp));
00526         }
00527 }
00528 
00529 /*
00530  * Return the amount of space in the bpobj which is:
00531  * mintxg < blk_birth <= maxtxg
00532  */
00533 int
00534 bpobj_space_range(bpobj_t *bpo, uint64_t mintxg, uint64_t maxtxg,
00535     uint64_t *usedp, uint64_t *compp, uint64_t *uncompp)
00536 {
00537         struct space_range_arg sra = { 0 };
00538         int err;
00539 
00540         /*
00541          * As an optimization, if they want the whole txg range, just
00542          * get bpo_bytes rather than iterating over the bps.
00543          */
00544         if (mintxg < TXG_INITIAL && maxtxg == UINT64_MAX && bpo->bpo_havecomp)
00545                 return (bpobj_space(bpo, usedp, compp, uncompp));
00546 
00547         sra.spa = dmu_objset_spa(bpo->bpo_os);
00548         sra.mintxg = mintxg;
00549         sra.maxtxg = maxtxg;
00550 
00551         err = bpobj_iterate_nofree(bpo, space_range_cb, &sra, NULL);
00552         *usedp = sra.used;
00553         *compp = sra.comp;
00554         *uncompp = sra.uncomp;
00555         return (err);
00556 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines