mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-22 02:27:36 +03:00
Allow rewrite skip cloned and snapshotted blocks
Rewrite of cloned and snapshotted blocks can allocate additional space, that may be undesired. In some cases it may have sense to still rewrite snapshotted blocks, expecting the snapshots to rotate with time, freeing space. In other cases rewrite of cloned blocks may be acceptable, despite persistent space usage increase. For this reason add them as separate flags to `zfs rewrite`. Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Reviewed-by: Rob Norris <robn@despairlabs.com> Reviewed-by: Ameer Hamza <ahamza@ixsystems.com> Signed-off-by: Alexander Motin <alexander.motin@TrueNAS.com> Closes #18179
This commit is contained in:
@@ -3943,4 +3943,26 @@ function pop_coredump_pattern
|
||||
esac
|
||||
}
|
||||
|
||||
#
|
||||
# get_same_blocks dataset1 path/to/file1 dataset2 path/to/file2 [key]
|
||||
#
|
||||
# Returns a space-separated list of the indexes (starting at 0) of the L0
|
||||
# blocks that are shared between both files (by first DVA and checksum).
|
||||
#
|
||||
function get_same_blocks # dataset1 file1 dataset2 file2 [key]
|
||||
{
|
||||
typeset KEY=$5
|
||||
if [ ${#KEY} -gt 0 ]; then
|
||||
KEY="--key=$KEY"
|
||||
fi
|
||||
typeset zdbout1=$(mktemp)
|
||||
typeset zdbout2=$(mktemp)
|
||||
zdb $KEY -vvvvv $1 -O $2 | \
|
||||
awk '/ L0 / { print l++ " " $3 " " $7 }' > $zdbout1
|
||||
zdb $KEY -vvvvv $3 -O $4 | \
|
||||
awk '/ L0 / { print l++ " " $3 " " $7 }' > $zdbout2
|
||||
echo $(sort -n $zdbout1 $zdbout2 | uniq -d | cut -f1 -d' ')
|
||||
rm -f $zdbout1 $zdbout2
|
||||
}
|
||||
|
||||
. ${STF_SUITE}/include/kstat.shlib
|
||||
|
||||
@@ -876,6 +876,8 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
|
||||
functional/cli_root/zfs_rewrite/setup.ksh \
|
||||
functional/cli_root/zfs_rewrite/zfs_rewrite.ksh \
|
||||
functional/cli_root/zfs_rewrite/zfs_rewrite_physical.ksh \
|
||||
functional/cli_root/zfs_rewrite/zfs_rewrite_skip_clone.ksh \
|
||||
functional/cli_root/zfs_rewrite/zfs_rewrite_skip_snapshot.ksh \
|
||||
functional/cli_root/zfs_rollback/cleanup.ksh \
|
||||
functional/cli_root/zfs_rollback/setup.ksh \
|
||||
functional/cli_root/zfs_rollback/zfs_rollback_001_pos.ksh \
|
||||
|
||||
@@ -35,27 +35,3 @@ function have_same_content
|
||||
log_must [ "$hash1" = "$hash2" ]
|
||||
}
|
||||
|
||||
#
|
||||
# get_same_blocks dataset1 path/to/file1 dataset2 path/to/file2
|
||||
#
|
||||
# Returns a space-separated list of the indexes (starting at 0) of the L0
|
||||
# blocks that are shared between both files (by first DVA and checksum).
|
||||
# Assumes that the two files have the same content, use have_same_content to
|
||||
# confirm that.
|
||||
#
|
||||
function get_same_blocks
|
||||
{
|
||||
KEY=$5
|
||||
if [ ${#KEY} -gt 0 ]; then
|
||||
KEY="--key=$KEY"
|
||||
fi
|
||||
typeset zdbout1=$(mktemp)
|
||||
typeset zdbout2=$(mktemp)
|
||||
zdb $KEY -vvvvv $1 -O $2 | \
|
||||
awk '/ L0 / { print l++ " " $3 " " $7 }' > $zdbout1
|
||||
zdb $KEY -vvvvv $3 -O $4 | \
|
||||
awk '/ L0 / { print l++ " " $3 " " $7 }' > $zdbout2
|
||||
echo $(sort -n $zdbout1 $zdbout2 | uniq -d | cut -f1 -d' ')
|
||||
rm -f $zdbout1 $zdbout2
|
||||
}
|
||||
|
||||
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
#!/bin/ksh -p
|
||||
# SPDX-License-Identifier: CDDL-1.0
|
||||
#
|
||||
# CDDL HEADER START
|
||||
#
|
||||
# The contents of this file are subject to the terms of the
|
||||
# Common Development and Distribution License (the "License").
|
||||
# You may not use this file except in compliance with the License.
|
||||
#
|
||||
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
# or https://opensource.org/licenses/CDDL-1.0.
|
||||
# See the License for the specific language governing permissions
|
||||
# and limitations under the License.
|
||||
#
|
||||
# When distributing Covered Code, include this CDDL HEADER in each
|
||||
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
# If applicable, add the following below this CDDL HEADER, with the
|
||||
# fields enclosed by brackets "[]" replaced with your own identifying
|
||||
# information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
#
|
||||
# CDDL HEADER END
|
||||
#
|
||||
|
||||
#
|
||||
# Copyright (c) 2026, iXsystems, Inc.
|
||||
#
|
||||
|
||||
# DESCRIPTION:
|
||||
# Verify zfs rewrite -C flag skips BRT-cloned blocks.
|
||||
#
|
||||
# STRATEGY:
|
||||
# 1. Create a test file and sync it.
|
||||
# 2. Clone the file using block cloning to share blocks via BRT.
|
||||
# 3. Rewrite clone with -C flag and verify blocks are NOT rewritten.
|
||||
# 4. Rewrite clone without -C flag and verify blocks ARE rewritten.
|
||||
|
||||
. $STF_SUITE/include/libtest.shlib
|
||||
|
||||
verify_runnable "global"
|
||||
|
||||
function cleanup
|
||||
{
|
||||
rm -rf $TESTDIR/*
|
||||
}
|
||||
|
||||
log_assert "zfs rewrite -C flag skips BRT-cloned blocks"
|
||||
|
||||
log_onexit cleanup
|
||||
|
||||
log_must zfs set recordsize=128k $TESTPOOL/$TESTFS
|
||||
|
||||
# Create source file (4 x 128KB = 4 blocks)
|
||||
log_must dd if=/dev/urandom of=$TESTDIR/source bs=128k count=4
|
||||
log_must sync_pool $TESTPOOL
|
||||
|
||||
# Clone the file using block cloning
|
||||
log_must clonefile -f $TESTDIR/source $TESTDIR/clone
|
||||
log_must sync_pool $TESTPOOL
|
||||
|
||||
# Verify blocks are actually shared initially
|
||||
typeset blocks=$(get_same_blocks $TESTPOOL/$TESTFS source \
|
||||
$TESTPOOL/$TESTFS clone)
|
||||
log_must [ "$blocks" = "0 1 2 3" ]
|
||||
|
||||
# Test 1: Rewrite clone WITH -C flag (should skip all cloned blocks)
|
||||
log_must zfs rewrite -C $TESTDIR/clone
|
||||
log_must sync_pool $TESTPOOL
|
||||
|
||||
# Blocks should still be shared (all blocks were skipped)
|
||||
typeset blocks=$(get_same_blocks $TESTPOOL/$TESTFS source \
|
||||
$TESTPOOL/$TESTFS clone)
|
||||
log_must [ "$blocks" = "0 1 2 3" ]
|
||||
|
||||
# Test 2: Rewrite clone WITHOUT -C flag (should rewrite all blocks)
|
||||
log_must zfs rewrite $TESTDIR/clone
|
||||
log_must sync_pool $TESTPOOL
|
||||
|
||||
# No blocks should be shared (clone has new blocks)
|
||||
typeset blocks=$(get_same_blocks $TESTPOOL/$TESTFS source \
|
||||
$TESTPOOL/$TESTFS clone)
|
||||
log_must [ -z "$blocks" ]
|
||||
|
||||
log_pass
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
#!/bin/ksh -p
|
||||
# SPDX-License-Identifier: CDDL-1.0
|
||||
#
|
||||
# CDDL HEADER START
|
||||
#
|
||||
# The contents of this file are subject to the terms of the
|
||||
# Common Development and Distribution License (the "License").
|
||||
# You may not use this file except in compliance with the License.
|
||||
#
|
||||
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
# or https://opensource.org/licenses/CDDL-1.0.
|
||||
# See the License for the specific language governing permissions
|
||||
# and limitations under the License.
|
||||
#
|
||||
# When distributing Covered Code, include this CDDL HEADER in each
|
||||
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
# If applicable, add the following below this CDDL HEADER, with the
|
||||
# fields enclosed by brackets "[]" replaced with your own identifying
|
||||
# information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
#
|
||||
# CDDL HEADER END
|
||||
#
|
||||
|
||||
#
|
||||
# Copyright (c) 2026, iXsystems, Inc.
|
||||
#
|
||||
|
||||
# DESCRIPTION:
|
||||
# Verify zfs rewrite -S flag skips snapshot-shared blocks.
|
||||
#
|
||||
# STRATEGY:
|
||||
# 1. Create a test file and sync it.
|
||||
# 2. Take a snapshot to share the blocks.
|
||||
# 3. Rewrite with -S flag and verify blocks are NOT rewritten.
|
||||
# 4. Rewrite without -S flag and verify blocks ARE rewritten.
|
||||
|
||||
. $STF_SUITE/include/libtest.shlib
|
||||
|
||||
function cleanup
|
||||
{
|
||||
rm -rf $TESTDIR/*
|
||||
zfs destroy -R $TESTPOOL/$TESTFS@snap1 2>/dev/null || true
|
||||
}
|
||||
|
||||
log_assert "zfs rewrite -S flag skips snapshot-shared blocks"
|
||||
|
||||
log_onexit cleanup
|
||||
|
||||
log_must zfs set recordsize=128k $TESTPOOL/$TESTFS
|
||||
|
||||
# Create test file (4 x 128KB = 4 blocks) and snapshot
|
||||
log_must dd if=/dev/urandom of=$TESTDIR/testfile bs=128k count=4
|
||||
log_must sync_pool $TESTPOOL
|
||||
log_must zfs snapshot $TESTPOOL/$TESTFS@snap1
|
||||
|
||||
# Test 1: Rewrite WITH -S flag (should skip all snapshot-shared blocks)
|
||||
log_must zfs rewrite -S $TESTDIR/testfile
|
||||
log_must sync_pool $TESTPOOL
|
||||
|
||||
# All blocks should still be shared (all blocks were skipped)
|
||||
typeset blocks=$(get_same_blocks $TESTPOOL/$TESTFS testfile \
|
||||
$TESTPOOL/$TESTFS@snap1 testfile)
|
||||
log_must [ "$blocks" = "0 1 2 3" ]
|
||||
|
||||
# Test 2: Rewrite WITHOUT -S flag (should rewrite all blocks)
|
||||
log_must zfs rewrite $TESTDIR/testfile
|
||||
log_must sync_pool $TESTPOOL
|
||||
|
||||
# No blocks should be shared (all blocks were rewritten)
|
||||
typeset blocks=$(get_same_blocks $TESTPOOL/$TESTFS testfile \
|
||||
$TESTPOOL/$TESTFS@snap1 testfile)
|
||||
log_must [ -z "$blocks" ]
|
||||
|
||||
log_pass
|
||||
Reference in New Issue
Block a user