|
20 | 20 | */
|
21 | 21 | /*
|
22 | 22 | * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
23 |
| - * Copyright (c) 2012, 2014 by Delphix. All rights reserved. |
| 23 | + * Copyright (c) 2012, 2016 by Delphix. All rights reserved. |
24 | 24 | */
|
25 | 25 |
|
26 | 26 | #include <sys/zfs_context.h>
|
@@ -61,6 +61,7 @@ typedef struct traverse_data {
|
61 | 61 | uint64_t td_hole_birth_enabled_txg;
|
62 | 62 | blkptr_cb_t *td_func;
|
63 | 63 | void *td_arg;
|
| 64 | + boolean_t td_realloc_possible; |
64 | 65 | } traverse_data_t;
|
65 | 66 |
|
66 | 67 | static int traverse_dnode(traverse_data_t *td, const dnode_phys_t *dnp,
|
@@ -228,18 +229,30 @@ traverse_visitbp(traverse_data_t *td, const dnode_phys_t *dnp,
|
228 | 229 |
|
229 | 230 | if (bp->blk_birth == 0) {
|
230 | 231 | /*
|
231 |
| - * Since this block has a birth time of 0 it must be a |
232 |
| - * hole created before the SPA_FEATURE_HOLE_BIRTH |
233 |
| - * feature was enabled. If SPA_FEATURE_HOLE_BIRTH |
234 |
| - * was enabled before the min_txg for this traveral we |
235 |
| - * know the hole must have been created before the |
236 |
| - * min_txg for this traveral, so we can skip it. If |
237 |
| - * SPA_FEATURE_HOLE_BIRTH was enabled after the min_txg |
238 |
| - * for this traveral we cannot tell if the hole was |
239 |
| - * created before or after the min_txg for this |
240 |
| - * traversal, so we cannot skip it. |
| 232 | + * Since this block has a birth time of 0 it must be one of |
| 233 | + * two things: a hole created before the |
| 234 | + * SPA_FEATURE_HOLE_BIRTH feature was enabled, or a hole |
| 235 | + * which has always been a hole in an object. |
| 236 | + * |
| 237 | + * If a file is written sparsely, then the unwritten parts of |
| 238 | + * the file were "always holes" -- that is, they have been |
| 239 | + * holes since this object was allocated. However, we (and |
| 240 | + * our callers) can not necessarily tell when an object was |
| 241 | + * allocated. Therefore, if it's possible that this object |
| 242 | + * was freed and then its object number reused, we need to |
| 243 | + * visit all the holes with birth==0. |
| 244 | + * |
| 245 | + * If it isn't possible that the object number was reused, |
| 246 | + * then if SPA_FEATURE_HOLE_BIRTH was enabled before we wrote |
| 247 | + * all the blocks we will visit as part of this traversal, |
| 248 | + * then this hole must have always existed, so we can skip |
| 249 | + * it. We visit blocks born after (exclusive) td_min_txg. |
| 250 | + * |
| 251 | + * Note that the meta-dnode cannot be reallocated. |
241 | 252 | */
|
242 |
| - if (td->td_hole_birth_enabled_txg < td->td_min_txg) |
| 253 | + if ((!td->td_realloc_possible || |
| 254 | + zb->zb_object == DMU_META_DNODE_OBJECT) && |
| 255 | + td->td_hole_birth_enabled_txg <= td->td_min_txg) |
243 | 256 | return (0);
|
244 | 257 | } else if (bp->blk_birth <= td->td_min_txg) {
|
245 | 258 | return (0);
|
@@ -347,6 +360,15 @@ traverse_visitbp(traverse_data_t *td, const dnode_phys_t *dnp,
|
347 | 360 |
|
348 | 361 | prefetch_dnode_metadata(td, mdnp, zb->zb_objset,
|
349 | 362 | DMU_META_DNODE_OBJECT);
|
| 363 | + /* |
| 364 | + * See the block comment above for the goal of this variable. |
| 365 | + * If the maxblkid of the meta-dnode is 0, then we know that |
| 366 | + * we've never had more than DNODES_PER_BLOCK objects in the |
| 367 | + * dataset, which means we can't have reused any object ids. |
| 368 | + */ |
| 369 | + if (osp->os_meta_dnode.dn_maxblkid == 0) |
| 370 | + td->td_realloc_possible = B_FALSE; |
| 371 | + |
350 | 372 | if (arc_buf_size(buf) >= sizeof (objset_phys_t)) {
|
351 | 373 | prefetch_dnode_metadata(td, gdnp, zb->zb_objset,
|
352 | 374 | DMU_GROUPUSED_OBJECT);
|
@@ -554,12 +576,13 @@ traverse_impl(spa_t *spa, dsl_dataset_t *ds, uint64_t objset, blkptr_t *rootbp,
|
554 | 576 | td->td_pfd = pd;
|
555 | 577 | td->td_flags = flags;
|
556 | 578 | td->td_paused = B_FALSE;
|
| 579 | + td->td_realloc_possible = (txg_start == 0 ? B_FALSE : B_TRUE); |
557 | 580 |
|
558 | 581 | if (spa_feature_is_active(spa, SPA_FEATURE_HOLE_BIRTH)) {
|
559 | 582 | VERIFY(spa_feature_enabled_txg(spa,
|
560 | 583 | SPA_FEATURE_HOLE_BIRTH, &td->td_hole_birth_enabled_txg));
|
561 | 584 | } else {
|
562 |
| - td->td_hole_birth_enabled_txg = 0; |
| 585 | + td->td_hole_birth_enabled_txg = UINT64_MAX; |
563 | 586 | }
|
564 | 587 |
|
565 | 588 | pd->pd_flags = flags;
|
|
0 commit comments