mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-24 11:18:52 +03:00
Restrict cloning with different properties
While technically its not a problem to clone between datasets with different properties, it might create expectation of new properties being applied during data move, while actually it won't happen. For copies and checksum it may mean incorrect safety expectations. For dedup, compression and special_small_blocks -- performance and space usage. New zfs_bclone_strict_properties tunable controls it. Reviewed-by: Rob Norris <robn@despairlabs.com> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Alexander Motin <alexander.motin@TrueNAS.com> Closes #18180
This commit is contained in:
@@ -69,6 +69,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
|
||||
@@ -1677,6 +1683,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);
|
||||
@@ -1758,6 +1779,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
|
||||
@@ -2116,6 +2157,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");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user