Skip to content
Open
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
4 changes: 4 additions & 0 deletions man/man4/zfs.4
Original file line number Diff line number Diff line change
Expand Up @@ -1448,6 +1448,10 @@ If this setting is 0, then even if feature@block_cloning is enabled,
using functions and system calls that attempt to clone blocks will act as
though the feature is disabled.
.
.It Sy zfs_bclone_strict_properties Ns = Ns Sy 1 Ns | Ns 0 Pq int
Restricts block cloning between datasets with different properties
(checksum, compression, copies, dedup, or special_small_blocks).
.
.It Sy zfs_bclone_wait_dirty Ns = Ns Sy 1 Ns | Ns 0 Pq int
When set to 1 the FICLONE and FICLONERANGE ioctls will wait for any dirty
data to be written to disk before proceeding.
Expand Down
44 changes: 44 additions & 0 deletions module/zfs/zfs_vnops.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@
*/
int zfs_bclone_enabled = 1;

/*
* Restricts block cloning between datasets with different properties
* (checksum, compression, copies, dedup, or special_small_blocks).
*/
int zfs_bclone_strict_properties = 1;

/*
* When set to 1 the FICLONE and FICLONERANGE ioctls will wait for any dirty
* data to be written to disk before proceeding. This ensures that the clone
Expand Down Expand Up @@ -1640,6 +1646,21 @@ zfs_clone_range(znode_t *inzp, uint64_t *inoffp, znode_t *outzp,
return (SET_ERROR(EXDEV));
}

/*
* Cloning between datasets with different properties is possible,
* but it may cause confusions when copying data between them and
* expecting new properties to apply.
*/
if (zfs_bclone_strict_properties && inos != outos &&
!inzfsvfs->z_issnap &&
(inos->os_checksum != outos->os_checksum ||
inos->os_compress != outos->os_compress ||
inos->os_copies != outos->os_copies ||
inos->os_dedup_checksum != outos->os_dedup_checksum)) {
zfs_exit_two(inzfsvfs, outzfsvfs, FTAG);
return (SET_ERROR(EXDEV));
}

error = zfs_verify_zp(inzp);
if (error == 0)
error = zfs_verify_zp(outzp);
Expand Down Expand Up @@ -1721,6 +1742,26 @@ zfs_clone_range(znode_t *inzp, uint64_t *inoffp, znode_t *outzp,

inblksz = inzp->z_blksz;

/*
* Cloning between datasets with different special_small_blocks would
* bypass storage tier migration that would occur with a regular copy.
*/
if (zfs_bclone_strict_properties && inos != outos &&
!inzfsvfs->z_issnap && spa_has_special(dmu_objset_spa(inos))) {
uint64_t in_smallblk = inos->os_zpl_special_smallblock;
uint64_t out_smallblk = outos->os_zpl_special_smallblock;
if (in_smallblk != out_smallblk) {
uint64_t min_smallblk = MIN(in_smallblk, out_smallblk);
uint64_t max_smallblk = MAX(in_smallblk, out_smallblk);
if (min_smallblk < inblksz &&
(inos->os_compress != ZIO_COMPRESS_OFF ||
max_smallblk >= inblksz)) {
error = SET_ERROR(EXDEV);
goto unlock;
}
}
}

/*
* We cannot clone into a file with different block size if we can't
* grow it (block size is already bigger, has more than one block, or
Expand Down Expand Up @@ -2079,6 +2120,9 @@ ZFS_MODULE_PARAM(zfs_vnops, zfs_vnops_, read_chunk_size, U64, ZMOD_RW,
ZFS_MODULE_PARAM(zfs, zfs_, bclone_enabled, INT, ZMOD_RW,
"Enable block cloning");

ZFS_MODULE_PARAM(zfs, zfs_, bclone_strict_properties, INT, ZMOD_RW,
"Restrict cross-dataset cloning with different properties");

ZFS_MODULE_PARAM(zfs, zfs_, bclone_wait_dirty, INT, ZMOD_RW,
"Wait for dirty blocks when cloning");

Expand Down
1 change: 1 addition & 0 deletions tests/zfs-tests/include/tunables.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ VOL_RECURSIVE vol.recursive UNSUPPORTED
VOL_REQUEST_SYNC vol.request_sync zvol_request_sync
VOL_USE_BLK_MQ UNSUPPORTED zvol_use_blk_mq
BCLONE_ENABLED bclone_enabled zfs_bclone_enabled
BCLONE_STRICT_PROPERTIES bclone_strict_properties zfs_bclone_strict_properties
BCLONE_WAIT_DIRTY bclone_wait_dirty zfs_bclone_wait_dirty
DIO_ENABLED dio_enabled zfs_dio_enabled
DIO_STRICT dio_strict zfs_dio_strict
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@ verify_runnable "both"

verify_crossfs_block_cloning

function cleanup
{
log_must zfs inherit compress $TESTSRCFS
log_must zfs inherit compress $TESTDSTFS
log_must zfs inherit recordsize $TESTSRCFS
log_must zfs inherit recordsize $TESTDSTFS
}
log_onexit cleanup

log_assert "Verify various corner cases in block cloning across datasets"

# Disable compression to make sure we won't use embedded blocks.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@ verify_runnable "both"

verify_crossfs_block_cloning

function cleanup
{
log_must zfs inherit compress $TESTSRCFS
log_must zfs inherit compress $TESTDSTFS
log_must zfs inherit recordsize $TESTSRCFS
log_must zfs inherit recordsize $TESTDSTFS
}
log_onexit cleanup

log_assert "Verify various corner cases in block cloning across datasets"

# Disable compression to make sure we won't use embedded blocks.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ verify_runnable "both"

verify_crossfs_block_cloning

function cleanup
{
log_must zfs inherit compress $TESTSRCFS
log_must zfs inherit compress $TESTDSTFS
}
log_onexit cleanup

log_assert "Verify block cloning properly clones regular files across datasets"

# Disable compression to make sure we won't use embedded blocks.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ verify_runnable "both"

verify_crossfs_block_cloning

function cleanup
{
log_must zfs inherit compress $TESTSRCFS
log_must zfs inherit compress $TESTDSTFS
}
log_onexit cleanup

log_assert "Verify block cloning properly clones small files (with embedded blocks) across datasets"

# Enable ZLE compression to make sure what is the maximum amount of data we
Expand Down
28 changes: 19 additions & 9 deletions tests/zfs-tests/tests/functional/bclone/bclone_diffprops_all.ksh
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,27 @@ verify_runnable "both"

verify_crossfs_block_cloning

save_tunable BCLONE_STRICT_PROPERTIES

function cleanup
{
restore_tunable BCLONE_STRICT_PROPERTIES
log_must zfs inherit checksum $TESTSRCFS
log_must zfs inherit compress $TESTSRCFS
log_must zfs inherit copies $TESTSRCFS
log_must zfs inherit recordsize $TESTSRCFS
log_must zfs inherit checksum $TESTDSTFS
log_must zfs inherit compress $TESTDSTFS
log_must zfs inherit copies $TESTDSTFS
log_must zfs inherit recordsize $TESTDSTFS
}
log_onexit cleanup

log_assert "Verify block cloning across datasets with different properties"

# Disable strict property checking to allow cross-dataset cloning with different properties
log_must set_tunable32 BCLONE_STRICT_PROPERTIES 0

log_must zfs set checksum=off $TESTSRCFS
log_must zfs set compress=off $TESTSRCFS
log_must zfs set copies=1 $TESTSRCFS
Expand Down Expand Up @@ -74,13 +93,4 @@ FILESIZE=$(random_int_between 2 32767)
FILESIZE=$((FILESIZE * 64))
bclone_test text $FILESIZE false $TESTSRCDIR $TESTDSTDIR

log_must zfs inherit checksum $TESTSRCFS
log_must zfs inherit compress $TESTSRCFS
log_must zfs inherit copies $TESTSRCFS
log_must zfs inherit recordsize $TESTSRCFS
log_must zfs inherit checksum $TESTDSTFS
log_must zfs inherit compress $TESTDSTFS
log_must zfs inherit copies $TESTDSTFS
log_must zfs inherit recordsize $TESTDSTFS

log_pass
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,23 @@ verify_runnable "both"

verify_crossfs_block_cloning

save_tunable BCLONE_STRICT_PROPERTIES

function cleanup
{
restore_tunable BCLONE_STRICT_PROPERTIES
log_must zfs inherit checksum $TESTSRCFS
log_must zfs inherit compress $TESTSRCFS
log_must zfs inherit checksum $TESTDSTFS
log_must zfs inherit compress $TESTDSTFS
}
log_onexit cleanup

log_assert "Verify block cloning across datasets with different checksum properties"

# Disable strict property checking to allow cross-dataset cloning with different properties
log_must set_tunable32 BCLONE_STRICT_PROPERTIES 0

log_must zfs set compress=off $TESTSRCFS
log_must zfs set compress=off $TESTDSTFS

Expand All @@ -56,7 +71,4 @@ for srcprop in "${checksum_prop_vals[@]}"; do
done
done

log_must zfs inherit checksum $TESTSRCFS
log_must zfs inherit checksum $TESTDSTFS

log_pass
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,21 @@ verify_runnable "both"

verify_crossfs_block_cloning

save_tunable BCLONE_STRICT_PROPERTIES

function cleanup
{
restore_tunable BCLONE_STRICT_PROPERTIES
log_must zfs inherit compress $TESTSRCFS
log_must zfs inherit compress $TESTDSTFS
}
log_onexit cleanup

log_assert "Verify block cloning across datasets with different compression properties"

# Disable strict property checking to allow cross-dataset cloning with different properties
log_must set_tunable32 BCLONE_STRICT_PROPERTIES 0

for srcprop in "${compress_prop_vals[@]}"; do
for dstprop in "${compress_prop_vals[@]}"; do
if [[ $srcprop == $dstprop ]]; then
Expand All @@ -53,7 +66,4 @@ for srcprop in "${compress_prop_vals[@]}"; do
done
done

log_must zfs inherit compress $TESTSRCFS
log_must zfs inherit compress $TESTDSTFS

log_pass
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,23 @@ verify_runnable "both"

verify_crossfs_block_cloning

save_tunable BCLONE_STRICT_PROPERTIES

function cleanup
{
restore_tunable BCLONE_STRICT_PROPERTIES
log_must zfs inherit copies $TESTSRCFS
log_must zfs inherit compress $TESTSRCFS
log_must zfs inherit copies $TESTDSTFS
log_must zfs inherit compress $TESTDSTFS
}
log_onexit cleanup

log_assert "Verify block cloning across datasets with different copies properties"

# Disable strict property checking to allow cross-dataset cloning with different properties
log_must set_tunable32 BCLONE_STRICT_PROPERTIES 0

log_must zfs set compress=off $TESTSRCFS
log_must zfs set compress=off $TESTDSTFS

Expand All @@ -53,7 +68,4 @@ for srcprop in "${copies_prop_vals[@]}"; do
done
done

log_must zfs inherit copies $TESTSRCFS
log_must zfs inherit copies $TESTDSTFS

log_pass
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,23 @@ verify_runnable "both"

verify_crossfs_block_cloning

save_tunable BCLONE_STRICT_PROPERTIES

function cleanup
{
restore_tunable BCLONE_STRICT_PROPERTIES
log_must zfs inherit recordsize $TESTSRCFS
log_must zfs inherit compress $TESTSRCFS
log_must zfs inherit recordsize $TESTDSTFS
log_must zfs inherit compress $TESTDSTFS
}
log_onexit cleanup

log_assert "Verify block cloning across datasets with different recordsize properties"

# Disable strict property checking to allow cross-dataset cloning with different properties
log_must set_tunable32 BCLONE_STRICT_PROPERTIES 0

log_must zfs set compress=off $TESTSRCFS
log_must zfs set compress=off $TESTDSTFS

Expand All @@ -59,7 +74,4 @@ for srcprop in "${bclone_recsize_prop_vals[@]}"; do
done
done

log_must zfs inherit recordsize $TESTSRCFS
log_must zfs inherit recordsize $TESTDSTFS

log_pass
12 changes: 9 additions & 3 deletions tests/zfs-tests/tests/functional/bclone/bclone_prop_sync.ksh
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ verify_runnable "both"

verify_crossfs_block_cloning

function cleanup
{
log_must zfs inherit compress $TESTSRCFS
log_must zfs inherit compress $TESTDSTFS
log_must zfs inherit sync $TESTSRCFS
log_must zfs inherit sync $TESTDSTFS
}
log_onexit cleanup

log_assert "Verify block cloning with all sync property settings"

log_must zfs set compress=zle $TESTSRCFS
Expand Down Expand Up @@ -64,7 +73,4 @@ for srcprop in "${sync_prop_vals[@]}"; do
done
done

log_must zfs inherit sync $TESTSRCFS
log_must zfs inherit sync $TESTDSTFS

log_pass
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@

verify_runnable "both"

function cleanup
{
log_must zfs inherit compress $TESTSRCFS
log_must zfs inherit recordsize $TESTSRCFS
}
log_onexit cleanup

log_assert "Verify various corner cases in block cloning within the same dataset"

# Disable compression to make sure we won't use embedded blocks.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@

verify_runnable "both"

function cleanup
{
log_must zfs inherit compress $TESTSRCFS
log_must zfs inherit recordsize $TESTSRCFS
}
log_onexit cleanup

log_assert "Verify various corner cases in block cloning within the same dataset"

# Disable compression to make sure we won't use embedded blocks.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@

verify_runnable "both"

function cleanup
{
log_must zfs inherit compress $TESTSRCFS
}
log_onexit cleanup

log_assert "Verify block cloning properly clones regular files within the same dataset"

# Disable compression to make sure we won't use embedded blocks.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@

verify_runnable "both"

function cleanup
{
log_must zfs inherit compress $TESTSRCFS
}
log_onexit cleanup

log_assert "Verify block cloning properly clones small files (with embedded blocks) within the same dataset"

# Enable ZLE compression to make sure what is the maximum amount of data we
Expand Down
Loading