Allow block cloning across encrypted datasets

When two datasets share the same master encryption key, it is safe
to clone encrypted blocks. Currently only snapshots and clones
of a dataset share with it the same encryption key.

Added a test for:
- Clone from encrypted sibling to encrypted sibling with
  non encrypted parent
- Clone from encrypted parent to inherited encrypted child
- Clone from child to sibling with encrypted parent
- Clone from snapshot to the original datasets
- Clone from foreign snapshot to a foreign dataset
- Cloning from non-encrypted to encrypted datasets
- Cloning from encrypted to non-encrypted datasets

Reviewed-by: Alexander Motin <mav@FreeBSD.org>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Original-patch-by: Pawel Jakub Dawidek <pawel@dawidek.net>
Signed-off-by: Kay Pedersen <mail@mkwg.de>
Closes #15544
This commit is contained in:
oromenahar
2023-12-05 20:03:48 +01:00
committed by GitHub
parent 55b764e062
commit c7b6119268
10 changed files with 236 additions and 25 deletions
+2 -4
View File
@@ -157,10 +157,8 @@
* (copying the file content to the new dataset and removing the source file).
* In that case Block Cloning will only be used briefly, because the BRT entries
* will be removed when the source is removed.
* Note: currently it is not possible to clone blocks between encrypted
* datasets, even if those datasets use the same encryption key (this includes
* snapshots of encrypted datasets). Cloning blocks between datasets that use
* the same keys should be possible and should be implemented in the future.
* Block Cloning across encrypted datasets is supported as long as both
* datasets share the same master key (e.g. snapshots and clones)
*
* Block Cloning flow through ZFS layers.
*
+34
View File
@@ -266,6 +266,40 @@ spa_crypto_key_compare(const void *a, const void *b)
return (0);
}
/*
* this compares a crypto key based on zk_guid. See comment on
* spa_crypto_key_compare for more information.
*/
boolean_t
dmu_objset_crypto_key_equal(objset_t *osa, objset_t *osb)
{
dsl_crypto_key_t *dcka = NULL;
dsl_crypto_key_t *dckb = NULL;
uint64_t obja, objb;
boolean_t equal;
spa_t *spa;
spa = dmu_objset_spa(osa);
if (spa != dmu_objset_spa(osb))
return (B_FALSE);
obja = dmu_objset_ds(osa)->ds_object;
objb = dmu_objset_ds(osb)->ds_object;
if (spa_keystore_lookup_key(spa, obja, FTAG, &dcka) != 0)
return (B_FALSE);
if (spa_keystore_lookup_key(spa, objb, FTAG, &dckb) != 0) {
spa_keystore_dsl_key_rele(spa, dcka, FTAG);
return (B_FALSE);
}
equal = (dcka->dck_key.zk_guid == dckb->dck_key.zk_guid);
spa_keystore_dsl_key_rele(spa, dcka, FTAG);
spa_keystore_dsl_key_rele(spa, dckb, FTAG);
return (equal);
}
static int
spa_key_mapping_compare(const void *a, const void *b)
{
+11 -14
View File
@@ -47,6 +47,7 @@
#include <sys/fs/zfs.h>
#include <sys/dmu.h>
#include <sys/dmu_objset.h>
#include <sys/dsl_crypt.h>
#include <sys/spa.h>
#include <sys/txg.h>
#include <sys/dbuf.h>
@@ -1097,6 +1098,16 @@ zfs_clone_range(znode_t *inzp, uint64_t *inoffp, znode_t *outzp,
return (SET_ERROR(EXDEV));
}
/*
* Cloning across encrypted datasets is possible only if they
* share the same master key.
*/
if (inos != outos && inos->os_encrypted &&
!dmu_objset_crypto_key_equal(inos, outos)) {
zfs_exit_two(inzfsvfs, outzfsvfs, FTAG);
return (SET_ERROR(EXDEV));
}
error = zfs_verify_zp(inzp);
if (error == 0)
error = zfs_verify_zp(outzp);
@@ -1280,20 +1291,6 @@ zfs_clone_range(znode_t *inzp, uint64_t *inoffp, znode_t *outzp,
*/
break;
}
/*
* Encrypted data is fine as long as it comes from the same
* dataset.
* TODO: We want to extend it in the future to allow cloning to
* datasets with the same keys, like clones or to be able to
* clone a file from a snapshot of an encrypted dataset into the
* dataset itself.
*/
if (BP_IS_PROTECTED(&bps[0])) {
if (inzfsvfs != outzfsvfs) {
error = SET_ERROR(EXDEV);
break;
}
}
/*
* Start a transaction.