Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BRT: Fix holes cloning #16007

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 13 additions & 13 deletions module/zfs/dmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -2265,11 +2265,13 @@ dmu_read_l0_bps(objset_t *os, uint64_t object, uint64_t offset, uint64_t length,

if (bp == NULL) {
/*
* The block was created in this transaction group,
* so it has no BP yet.
* The file size was increased, but the block was never
* written, otherwise we would either have the block
* pointer or the dirty record and would not get here.
* It is effectively a hole, so report it as such.
*/
error = SET_ERROR(EAGAIN);
goto out;
BP_ZERO(&bps[i]);
continue;
}
/*
* Make sure we clone only data blocks.
Expand Down Expand Up @@ -2361,19 +2363,17 @@ dmu_brt_clone(objset_t *os, uint64_t object, uint64_t offset, uint64_t length,
ASSERT3U(dr->dr_txg, ==, tx->tx_txg);
dl = &dr->dt.dl;
dl->dr_overridden_by = *bp;
dl->dr_brtwrite = B_TRUE;
dl->dr_override_state = DR_OVERRIDDEN;
if (BP_IS_HOLE(bp)) {
BP_SET_LOGICAL_BIRTH(&dl->dr_overridden_by, 0);
BP_SET_PHYSICAL_BIRTH(&dl->dr_overridden_by, 0);
} else {
BP_SET_LOGICAL_BIRTH(&dl->dr_overridden_by,
dr->dr_txg);
if (!BP_IS_HOLE(bp) || BP_GET_LOGICAL_BIRTH(bp) != 0) {
if (!BP_IS_EMBEDDED(bp)) {
BP_SET_PHYSICAL_BIRTH(&dl->dr_overridden_by,
BP_SET_BIRTH(&dl->dr_overridden_by, dr->dr_txg,
BP_GET_BIRTH(bp));
} else {
BP_SET_LOGICAL_BIRTH(&dl->dr_overridden_by,
dr->dr_txg);
}
}
dl->dr_brtwrite = B_TRUE;
dl->dr_override_state = DR_OVERRIDDEN;

mutex_exit(&db->db_mtx);

Expand Down
47 changes: 26 additions & 21 deletions tests/zfs-tests/tests/functional/bclone/bclone_common.kshlib
Original file line number Diff line number Diff line change
Expand Up @@ -97,20 +97,19 @@ function verify_pool_prop_eq

function verify_pool_props
{
typeset -r dsize=$1
typeset -r ratio=$2
typeset -r oused=$1
typeset -r osaved=$2
typeset dsize=$3
typeset ratio=$4

if [[ $dsize -eq 0 ]]; then
verify_pool_prop_eq bcloneused 0
verify_pool_prop_eq bclonesaved 0
verify_pool_prop_eq bcloneratio 1.00
else
if [[ $ratio -eq 1 ]]; then
verify_pool_prop_eq bcloneused 0
else
verify_pool_prop_eq bcloneused $dsize
fi
verify_pool_prop_eq bclonesaved $((dsize*(ratio-1)))
ratio=1
elif [[ $ratio -eq 1 ]]; then
dsize=0
fi
verify_pool_prop_eq bcloneused $(($oused+$dsize))
verify_pool_prop_eq bclonesaved $(($osaved+dsize*(ratio-1)))
if [[ $oused -eq 0 ]]; then
verify_pool_prop_eq bcloneratio "${ratio}.00"
fi
}
Expand All @@ -124,16 +123,22 @@ function bclone_test
typeset -r srcdir=$4
typeset -r dstdir=$5
typeset dsize
typeset oused
typeset osaved

typeset -r original="${srcdir}/original"
typeset -r clone="${dstdir}/clone"

log_note "Testing file copy with datatype $datatype, file size $filesize, embedded $embedded"

# Save current block cloning stats for later use.
sync_pool $TESTPOOL
oused=$(get_pool_prop bcloneused $TESTPOOL)
osaved=$(get_pool_prop bclonesaved $TESTPOOL)

# Create a test file with known content.
case $datatype in
random|text)
sync_pool $TESTPOOL
if [[ $datatype = "random" ]]; then
dd if=/dev/urandom of=$original bs=$filesize count=1 2>/dev/null
else
Expand All @@ -146,13 +151,13 @@ function bclone_test
sync_pool $TESTPOOL
# It is hard to predict block sizes that will be used,
# so just do one clone and take it from bcloneused.
filesize=$(zpool get -Hp -o value bcloneused $TESTPOOL)
dsize=$(get_pool_prop bcloneused $TESTPOOL)
dsize=$(($dsize-$oused))
if [[ $embedded = "false" ]]; then
log_must test $filesize -gt 0
log_must test $dsize -gt 0
fi
rm -f "${clone}-tmp"
sync_pool $TESTPOOL
dsize=$filesize
;;
hole)
log_must truncate_test -s $filesize -f $original
Expand Down Expand Up @@ -217,7 +222,7 @@ function bclone_test
test_file_integrity $original_checksum "${clone}4" $filesize
test_file_integrity $original_checksum "${clone}5" $filesize

verify_pool_props $dsize 7
verify_pool_props $oused $osaved $dsize 7

# Clear cache and test after fresh import.
log_must zpool export $TESTPOOL
Expand All @@ -240,7 +245,7 @@ function bclone_test

sync_pool $TESTPOOL

verify_pool_props $dsize 11
verify_pool_props $oused $osaved $dsize 11

log_must zpool export $TESTPOOL
log_must zpool import $TESTPOOL
Expand Down Expand Up @@ -268,19 +273,19 @@ function bclone_test
test_file_integrity $original_checksum "${clone}8" $filesize
test_file_integrity $original_checksum "${clone}9" $filesize

verify_pool_props $dsize 6
verify_pool_props $oused $osaved $dsize 6

rm -f "${clone}0" "${clone}2" "${clone}4" "${clone}8" "${clone}9"

sync_pool $TESTPOOL

test_file_integrity $original_checksum "${clone}6" $filesize

verify_pool_props $dsize 1
verify_pool_props $oused $osaved $dsize 1

rm -f "${clone}6"

sync_pool $TESTPOOL

verify_pool_props $dsize 1
verify_pool_props $oused $osaved $dsize 1
}
20 changes: 15 additions & 5 deletions tests/zfs-tests/tests/functional/bclone/bclone_corner_cases.kshlib
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ function bclone_corner_cases_init
export SECOND_HALF_ORIG0_CHECKSUM=$(second_half_checksum $ORIG0)
export SECOND_HALF_ORIG1_CHECKSUM=$(second_half_checksum $ORIG1)
export SECOND_HALF_ORIG2_CHECKSUM=$(second_half_checksum $ORIG2)
export ZEROS_CHECKSUM=$(dd if=/dev/zero bs=$HALFRECORDSIZE count=1 | sha256digest)
export ZEROS_CHECKSUM=$(dd if=/dev/zero bs=$HALFRECORDSIZE count=1 2>/dev/null | sha256digest)
export FIRST_HALF_CHECKSUM=""
export SECOND_HALF_CHECKSUM=""
}
Expand Down Expand Up @@ -210,13 +210,20 @@ function bclone_corner_cases_test
typeset -r dstdir=$2
typeset limit=$3
typeset -i count=0
typeset oused
typeset osaved

if [[ $srcdir != "count" ]]; then
if [[ -n "$limit" ]]; then
typeset -r total_count=$(bclone_corner_cases_test count)
limit=$(random_int_between 1 $total_count $((limit*2)) | sort -nu | head -n $limit | xargs)
fi
bclone_corner_cases_init $srcdir $dstdir

# Save current block cloning stats for later use.
sync_pool $TESTPOOL
oused=$(get_pool_prop bcloneused $TESTPOOL)
osaved=$(get_pool_prop bclonesaved $TESTPOOL)
fi

#
Expand Down Expand Up @@ -285,21 +292,24 @@ function bclone_corner_cases_test
overwrite_clone "$second_overwrite"

if checksum_compare $read_after; then
log_note "existing: $existing / cached: $cached / first_clone: $first_clone / first_overwrite: $first_overwrite / read_before: $read_before / second_clone: $second_clone / read_after: $read_after"
log_note "existing: $existing / cached: $cached / first_clone: $first_clone / first_overwrite: $first_overwrite / read_before: $read_before / second_clone: $second_clone / second_overwrite: $second_overwrite / read_after: $read_after"
else
log_fail "FAIL: existing: $existing / cached: $cached / first_clone: $first_clone / first_overwrite: $first_overwrite / read_before: $read_before / second_clone: $second_clone / read_after: $read_after"
log_fail "FAIL: existing: $existing / cached: $cached / first_clone: $first_clone / first_overwrite: $first_overwrite / read_before: $read_before / second_clone: $second_clone / second_overwrite: $second_overwrite / read_after: $read_after"
fi

log_must zpool export $TESTPOOL
log_must zpool import $TESTPOOL

if checksum_compare "yes"; then
log_note "existing: $existing / cached: $cached / first_clone: $first_clone / first_overwrite: $first_overwrite / read_before: $read_before / second_clone: $second_clone / read_after: $read_after / read_next_txg"
log_note "existing: $existing / cached: $cached / first_clone: $first_clone / first_overwrite: $first_overwrite / read_before: $read_before / second_clone: $second_clone / second_overwrite: $second_overwrite / read_after: $read_after / read_next_txg"
else
log_fail "FAIL: existing: $existing / cached: $cached / first_clone: $first_clone / first_overwrite: $first_overwrite / read_before: $read_before / second_clone: $second_clone / read_after: $read_after / read_next_txg"
log_fail "FAIL: existing: $existing / cached: $cached / first_clone: $first_clone / first_overwrite: $first_overwrite / read_before: $read_before / second_clone: $second_clone / second_overwrite: $second_overwrite / read_after: $read_after / read_next_txg"
fi

rm -f "$CLONE"
sync_pool $TESTPOOL
verify_pool_prop_eq bcloneused $oused
verify_pool_prop_eq bclonesaved $osaved
done
done
done
Expand Down
Loading