Skip to content

Commit

Permalink
Allow block cloning across encrypted datasets.
Browse files Browse the repository at this point in the history
Block cloning is now possible between two encrypted datasets that share
the same encryption root.

Signed-off-by: Pawel Jakub Dawidek <[email protected]>
  • Loading branch information
pjd committed Apr 2, 2023
1 parent 9fa007d commit f4c3a38
Show file tree
Hide file tree
Showing 8 changed files with 31 additions and 23 deletions.
1 change: 1 addition & 0 deletions include/sys/dmu.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ struct zio;
struct blkptr;
struct zap_cursor;
struct dsl_dataset;
struct dsl_dir;
struct dsl_pool;
struct dnode;
struct drr_begin;
Expand Down
1 change: 1 addition & 0 deletions include/sys/dmu_objset.h
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ boolean_t dmu_objset_userspace_present(objset_t *os);
boolean_t dmu_objset_userobjused_enabled(objset_t *os);
boolean_t dmu_objset_userobjspace_upgradable(objset_t *os);
boolean_t dmu_objset_userobjspace_present(objset_t *os);
uint64_t dmu_objset_encryption_root(objset_t *os);
boolean_t dmu_objset_incompatible_encryption_version(objset_t *os);
boolean_t dmu_objset_projectquota_enabled(objset_t *os);
boolean_t dmu_objset_projectquota_present(objset_t *os);
Expand Down
1 change: 1 addition & 0 deletions include/sys/dsl_crypt.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ void key_mapping_rele(spa_t *spa, dsl_key_mapping_t *km, const void *tag);
int spa_keystore_lookup_key(spa_t *spa, uint64_t dsobj, const void *tag,
dsl_crypto_key_t **dck_out);

int dsl_dir_get_encryption_root_ddobj(dsl_dir_t *dd, uint64_t *rddobj);
int dsl_crypto_populate_key_nvlist(struct objset *os,
uint64_t from_ivset_guid, nvlist_t **nvl_out);
int dsl_crypto_recv_raw_key_check(struct dsl_dataset *ds,
Expand Down
6 changes: 3 additions & 3 deletions man/man7/zpool-features.7
Original file line number Diff line number Diff line change
Expand Up @@ -353,9 +353,9 @@ When this feature is enabled ZFS will use block cloning for operations like
Block cloning allows to create multiple references to a single block.
It is much faster than copying the data (as the actual data is neither read nor
written) and takes no additional space.
Blocks can be cloned across datasets under some conditions (like disabled
encryption and equal
.Nm recordsize ) .
Blocks can be cloned across datasets under some conditions (like equal
.Nm recordsize ,
the same encryption root, etc.).
.Pp
This feature becomes
.Sy active
Expand Down
6 changes: 2 additions & 4 deletions module/zfs/brt.c
Original file line number Diff line number Diff line change
Expand Up @@ -156,10 +156,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 encryption root.
*
* Block Cloning flow through ZFS layers.
*
Expand Down
12 changes: 12 additions & 0 deletions module/zfs/dmu_objset.c
Original file line number Diff line number Diff line change
Expand Up @@ -2973,6 +2973,18 @@ dmu_objset_find(const char *name, int func(const char *, void *), void *arg,
return (error);
}

uint64_t
dmu_objset_encryption_root(objset_t *os)
{
dsl_dir_t *dd = os->os_dsl_dataset->ds_dir;
uint64_t encroot = 0;

if (dsl_dir_get_encryption_root_ddobj(dd, &encroot) != 0) {
return (0);
}
return (encroot);
}

boolean_t
dmu_objset_incompatible_encryption_version(objset_t *os)
{
Expand Down
2 changes: 1 addition & 1 deletion module/zfs/dsl_crypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ spa_keystore_fini(spa_keystore_t *sk)
rw_destroy(&sk->sk_dk_lock);
}

static int
int
dsl_dir_get_encryption_root_ddobj(dsl_dir_t *dd, uint64_t *rddobj)
{
if (dd->dd_crypto_obj == 0)
Expand Down
25 changes: 10 additions & 15 deletions module/zfs/zfs_vnops.c
Original file line number Diff line number Diff line change
Expand Up @@ -1107,6 +1107,16 @@ zfs_clone_range(znode_t *inzp, uint64_t *inoffp, znode_t *outzp,
return (SET_ERROR(EXDEV));
}

/*
* Cloning across encrypted dataset is possible only if they share
* the same encryption root.
*/
if (inos != outos && dmu_objset_encryption_root(inos) !=
dmu_objset_encryption_root(outos)) {
zfs_exit_two(inzfsvfs, outzfsvfs, FTAG);
return (SET_ERROR(EXDEV));
}

/*
* We don't copy source file's flags that's why we don't allow to clone
* files that are in quarantine.
Expand Down Expand Up @@ -1266,21 +1276,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) {
dmu_tx_abort(tx);
error = SET_ERROR(EXDEV);
break;
}
}

dmu_tx_hold_sa(tx, outzp->z_sa_hdl, B_FALSE);
db = (dmu_buf_impl_t *)sa_get_db(outzp->z_sa_hdl);
Expand Down

0 comments on commit f4c3a38

Please sign in to comment.