Skip to content

Commit a519568

Browse files
committed
Fix livelist assertions for dedup and cloning
Two block pointers in livelist pointing to the same location may be caused not only by dedup, but also by block cloning. We should not assert D bit set in them. Two block pointers in livelist pointing to the same location may have different logical birth time in case of dedup or cloning. We should assert identical physical birth time instead. Assert identical physical block size between pointers in addition to checksum, since that is what checksums are calculated on. Reviewed-by: Matthew Ahrens <[email protected]> Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Alexander Motin <[email protected]> Sponsored by: iXsystems, Inc. Closes openzfs#15732
1 parent 59e3bf5 commit a519568

File tree

1 file changed

+14
-17
lines changed

1 file changed

+14
-17
lines changed

module/zfs/dsl_deadlist.c

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,8 +1000,6 @@ livelist_compare(const void *larg, const void *rarg)
10001000
/* if vdevs are equal, sort by offsets. */
10011001
uint64_t l_dva0_offset = DVA_GET_OFFSET(&l->blk_dva[0]);
10021002
uint64_t r_dva0_offset = DVA_GET_OFFSET(&r->blk_dva[0]);
1003-
if (l_dva0_offset == r_dva0_offset)
1004-
ASSERT3U(l->blk_birth, ==, r->blk_birth);
10051003
return (TREE_CMP(l_dva0_offset, r_dva0_offset));
10061004
}
10071005

@@ -1016,9 +1014,9 @@ struct livelist_iter_arg {
10161014
* and used to match up ALLOC/FREE pairs. ALLOC'd blkptrs without a
10171015
* corresponding FREE are stored in the supplied bplist.
10181016
*
1019-
* Note that multiple FREE and ALLOC entries for the same blkptr may
1020-
* be encountered when dedup is involved. For this reason we keep a
1021-
* refcount for all the FREE entries of each blkptr and ensure that
1017+
* Note that multiple FREE and ALLOC entries for the same blkptr may be
1018+
* encountered when dedup or block cloning is involved. For this reason we
1019+
* keep a refcount for all the FREE entries of each blkptr and ensure that
10221020
* each of those FREE entries has a corresponding ALLOC preceding it.
10231021
*/
10241022
static int
@@ -1037,6 +1035,13 @@ dsl_livelist_iterate(void *arg, const blkptr_t *bp, boolean_t bp_freed,
10371035
livelist_entry_t node;
10381036
node.le_bp = *bp;
10391037
livelist_entry_t *found = avl_find(avl, &node, NULL);
1038+
if (found) {
1039+
ASSERT3U(BP_GET_PSIZE(bp), ==, BP_GET_PSIZE(&found->le_bp));
1040+
ASSERT3U(BP_GET_CHECKSUM(bp), ==,
1041+
BP_GET_CHECKSUM(&found->le_bp));
1042+
ASSERT3U(BP_PHYSICAL_BIRTH(bp), ==,
1043+
BP_PHYSICAL_BIRTH(&found->le_bp));
1044+
}
10401045
if (bp_freed) {
10411046
if (found == NULL) {
10421047
/* first free entry for this blkptr */
@@ -1046,10 +1051,10 @@ dsl_livelist_iterate(void *arg, const blkptr_t *bp, boolean_t bp_freed,
10461051
e->le_refcnt = 1;
10471052
avl_add(avl, e);
10481053
} else {
1049-
/* dedup block free */
1050-
ASSERT(BP_GET_DEDUP(bp));
1051-
ASSERT3U(BP_GET_CHECKSUM(bp), ==,
1052-
BP_GET_CHECKSUM(&found->le_bp));
1054+
/*
1055+
* Deduped or cloned block free. We could assert D bit
1056+
* for dedup, but there is no such one for cloning.
1057+
*/
10531058
ASSERT3U(found->le_refcnt + 1, >, found->le_refcnt);
10541059
found->le_refcnt++;
10551060
}
@@ -1065,14 +1070,6 @@ dsl_livelist_iterate(void *arg, const blkptr_t *bp, boolean_t bp_freed,
10651070
/* all tracked free pairs have been matched */
10661071
avl_remove(avl, found);
10671072
kmem_free(found, sizeof (livelist_entry_t));
1068-
} else {
1069-
/*
1070-
* This is definitely a deduped blkptr so
1071-
* let's validate it.
1072-
*/
1073-
ASSERT(BP_GET_DEDUP(bp));
1074-
ASSERT3U(BP_GET_CHECKSUM(bp), ==,
1075-
BP_GET_CHECKSUM(&found->le_bp));
10761073
}
10771074
}
10781075
}

0 commit comments

Comments
 (0)