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